---
# System prepended metadata

title: G麻開門

---

## GCP簡單入門手冊
先去看完古古的30天(理論)介紹
https://ithelp.ithome.com.tw/m/articles/10318700

首先要先有信用卡和Google帳戶
然後GCP服務眾多
目標是可以把完整專案丟上雲端，並且可以遠程調用(API或是完整Web服務)

然後因為很重要
所以我會每隔一段就附上

--- 
▼▼▼▼▼▼▼▼
[**<font style='color:red; font-size:30px;'>強烈警告</font>**](#強烈警告)
▲▲▲▲▲▲▲▲

--- 
## 啟用GCP服務
先啟用服務和試用
google搜尋<font style='color:red;'>GCP</font>就可以看到
![image](https://hackmd.io/_uploads/S1R3IWj-1l.png)

進入之後可以看到畫面，點擊==免費試用==
![image](https://hackmd.io/_uploads/rJsEDbj-yg.png)

然後就把該填的資料填一填
![image](https://hackmd.io/_uploads/ryYvPbjWJl.png =60%x)
![image](https://hackmd.io/_uploads/rkYTDboWyx.png)
然後下面要填寫信用卡
![image](https://hackmd.io/_uploads/S101dZsZJg.png)

完成啟用之後就可以進入到GCP首頁，可以看到啟用了，也有顯示免費試用的抵免額(300鎂轉台幣)
![image](https://hackmd.io/_uploads/Syuhd-sW1e.png)

可以點擊==資訊主業==，看更詳細內容，也都有帳單金額，不用擔心
![image](https://hackmd.io/_uploads/rJCQKZjZ1e.png)
![image](https://hackmd.io/_uploads/rJVDYZjZkx.png)

點擊上面的選單可以看到，目前所在就是系統自動創建的專案，有需要也可以自己做新增或修改
![image](https://hackmd.io/_uploads/BkOWsWiZJe.png)

名稱可以在這邊改
![image](https://hackmd.io/_uploads/S1uLsZoWJg.png =50%x)

但會有一些名稱限制
![image](https://hackmd.io/_uploads/rkGcobjZJx.png)

儲存之後就可以看到
![image](https://hackmd.io/_uploads/rJB0oWibJg.png)


## Compute Engine(VM)-練習

### 簡單部屬
先簡單開個機器來使用
點擊==Compute Engine==，可以進到相關管理畫面，就直接啟用
![image](https://hackmd.io/_uploads/HJpP2Zi-kg.png =50%x)

啟用之後就可以看到這個畫面，現在還沒有任何VM
![image](https://hackmd.io/_uploads/SJn-V7oZ1e.png)

這邊就點建立執行個體，進入設置頁面
地區可以選台灣，先選最便宜的機器(==f1-micro==)
![image](https://hackmd.io/_uploads/rJEmFXs-Jg.png)
![image](https://hackmd.io/_uploads/SJBAKmsZ1x.png =80%x)

這邊可以指定作業系統
![image](https://hackmd.io/_uploads/Hy-KcmsW1e.png)

==注意==會依照作業系統不同而有不同的收費，這邊先選<font style='color:red;'>Ubuntu</font>就好
![image](https://hackmd.io/_uploads/HkZW3XiZyl.png)
![image](https://hackmd.io/_uploads/HJ42nXjbye.png)
![image](https://hackmd.io/_uploads/S1KN67s-Jl.png =60%x)

防火牆部分先勾==HTTP==和==HTTPS==
![image](https://hackmd.io/_uploads/Hyv6TQj-1x.png)

其他部分就先不用設定，就直接點建立，先建起來
![image](https://hackmd.io/_uploads/S1btR7obye.png)
馬上就好了
然後點擊SSH的按鈕，就可以連線到該機器
![image](https://hackmd.io/_uploads/r1JlJNjZyx.png)
![image](https://hackmd.io/_uploads/BkiVJVsWJl.png)
然後就可以開始下指令操作，先==sudo apt update==
![image](https://hackmd.io/_uploads/H1zcyEjbyx.png)
![image](https://hackmd.io/_uploads/Sk2RyNj-Jx.png)
OK
先安裝apache2，==sudo apt install apache2 -y==
![image](https://hackmd.io/_uploads/Syp7xEiWye.png)

安裝好就可以測試，看看外部IP打開能不能連上(==要改成http，因為https還沒配置==)
![image](https://hackmd.io/_uploads/H1EAl4oZJx.png)
![image](https://hackmd.io/_uploads/S11V-NsZyl.png)
應該就可以看見apache2的畫面了
![image](https://hackmd.io/_uploads/Byj8bEjb1g.png =60%x)

接下來測試一下靜態網頁
這邊都先不管域名，目前連線到對外IP的畫面就是apache2的畫面
默認路徑為 ==/var/www/html/==
先移動到該路徑底下
![image](https://hackmd.io/_uploads/Syv4n4jZyl.png)

然後創建一個自己名稱的資料夾，==sudo mkdir -p==
index.html是apache2默認建立的首頁
![image](https://hackmd.io/_uploads/r12cnEi-yl.png)

然後這邊先修改權限
==sudo chown -R \$USER:$USER testweb.com/==
==sudo chmod -R 755 /var/www==
![image](https://hackmd.io/_uploads/rkz6a4sbyl.png)

接下來就是在新建的資料夾底下新增想呈現的靜態頁面，==sudo vim index.html==
![image](https://hackmd.io/_uploads/BJPvC4iWkg.png)
至於內容，就隨便寫個html標籤吧
```html=
<html>
    <head>
        <title>TestTitle123</title>
    </head>
    <body>
        <h1>Welcome to testWeb</h1>
    </body>
</html>
```
好了就存檔，記得確定一下內容
![image](https://hackmd.io/_uploads/ry4aRVsbkx.png)

要顯示的頁面處理好了，接下來就是要==更改預設路徑的指向到剛剛新增的路徑==
先移動到路徑 ==/etc/apache2/sites-available/== 底下
![image](https://hackmd.io/_uploads/rJAulHsW1e.png)

可以看到底下的文件==000-default.conf== 就是配置文件
![image](https://hackmd.io/_uploads/BkBCeSoW1g.png)

這邊就直接複製一份==sudo cp 000-default.conf testweb.com.conf==到本地
![image](https://hackmd.io/_uploads/rkhXZHiZJl.png)

然後一樣vim編輯內容
![image](https://hackmd.io/_uploads/SJVgMrsZyl.png)
把內容改成
![image](https://hackmd.io/_uploads/HJ8IMBiWkg.png)
主要就是把root指向改到剛剛新增的路徑下，好了一樣存檔退出

再來就是要把預設的配置檔改成使用剛剛複製的新配置
==sudo a2ensite testweb.com.conf== 指向新配置
==sudo a2dissite 000-default.conf== 停止舊配置
然後下指令時會顯示需要重啟apache2，==sudo systemctl reload apache2==
![image](https://hackmd.io/_uploads/SJiUQHib1e.png)
這樣就更改完配置指向了
可以測試==sudo apache2ctl configtest==
![image](https://hackmd.io/_uploads/SyFhErjW1e.png)

然後就重新整理剛剛的對外IP的頁面，應該就會指向到新增的靜態頁面了
![image](https://hackmd.io/_uploads/S1K_BriWke.png)

### 遠端連線(SFTP_FileZilla)
如果要更新文件或是有其他比較複雜的動作，不想只依靠指令，可以利用fileZilla連線操作，但要透過SFTP連線需要設定雙向金鑰
1. 先在服務端輸入指令==ssh-keygen -t rsa -b 2048 -f ~/.ssh/gcp_key==
會產生gcp_key的金鑰檔案
![image](https://hackmd.io/_uploads/Hy7BnSs-1x.png)
2. 複製==gcp_key.pub==檔案內容
![image](https://hackmd.io/_uploads/Sy6d2BsWJl.png)
3. 進入VM點擊編輯，往下看到金鑰，新增並且把剛剛複製的金鑰貼上並儲存
![image](https://hackmd.io/_uploads/B1032Sj-yl.png)
![image](https://hackmd.io/_uploads/BkdBpSjWyg.png)
4. 回到VM首頁，複製對外IP
![image](https://hackmd.io/_uploads/ryEsaHjW1x.png)
5. 開啟fileZilla，開啟檔案>站台管理
![image](https://hackmd.io/_uploads/H11FULobJx.png)
金鑰檔案的部分就回到ubuntu終端，這次複製==gcp_key==文件內容，然後本地隨便建立一個文件儲存，之後把連線金鑰指向該文件
![image](https://hackmd.io/_uploads/SyinASs-kx.png =70%x)
![image](https://hackmd.io/_uploads/HkXjlIi-1e.png =70%x)
好了之後點選連線，就可以成功連線到系統了
![image](https://hackmd.io/_uploads/Syl9JLjbJg.png)

### Free-domain(DNS)
現在可以利用對外IP來連線到雲端服務器的頁面
但要記憶IP實在麻煩，所以接下來會需要綁個域名到IP，就需要用到DNS
網上有很多DNS商，這邊就用免費的[Duck DNS](https://www.duckdns.org/)
只要登入就可以使用，很方便 (當然還是有很多其他免費DNS，選喜歡的就好)
![image](https://hackmd.io/_uploads/ByojIElzyg.png)
1. 輸入想建立的域名，點擊add domain，就會在下面新增剛剛創建的<font style='color:red;'>domainName</font>.duckdns.org
2. 把GCP服務的對外external IP綁到這個current IP
3. 測試連線到<span>domainName</span>.duckdns.org，應該就可以連上服務了
![image](https://hackmd.io/_uploads/ryY_HEgGkx.png)

但還有一個問題，就是現在GCP的服務IP還是dynamic IP，如果服務重啟IP就會改變，那這個綁定的domain就會失效，還需要手動更改，所以接下來就是要在服務器上利用bash排程和DuckDNS的API來更新綁定的IP
1. 先回到GCP，開啟服務終端
![image](https://hackmd.io/_uploads/BkNOdVgM1g.png =70%x)
2. 先安裝curl，等下要用來裝其他東西
    ```bash=
    sudo apt update
    sudo apt install curl
    ```
    ![image](https://hackmd.io/_uploads/rkeBFExf1g.png =70%x)
3. 建個duckdns的資料夾
    ```bash=
    mkdir ~/duckdns
    cd ~/duckdns
    ```
    ![image](https://hackmd.io/_uploads/By1u5VxGkl.png)
4. nano新增一個bash文件，內容放上修改IP的API和帳戶Token，也可以在[官方教學](https://www.duckdns.org/install.jsp)找到
這邊有稍微修改一下log，加上時間，並且用 ==>>== 不用複寫的方式，整理log格式
    ```bash=
    #!/bin/bash
    datetime=$(date '+%Y-%m-%d %H:%M:%S')
    result=$(echo url="https://www.duckdns.org/update?domains=exampledomain&token=yourToken&ip=" | curl -k -K -)
    echo "[$datetime: $result]" >> ~/duckdns/duck.log
    ```
    ![image](https://hackmd.io/_uploads/B190GBgzJx.png =70%x)
    ![image](https://hackmd.io/_uploads/SkP8TBeMyg.png)
5. 編輯文件權限，這樣bash部分就完成了
    ```bash=
    chmod +x duckdns.sh
    ```
    ![image](https://hackmd.io/_uploads/rJSAmSxfye.png)
6. 接下來就是建立Cron排程，編輯器一樣nano就好
    ```bash=
    crontab -e
    ```
    內容如下，就是寫Cron
    ```bash=
    */5 * * * * ~/duckdns/duckdns.sh >/dev/null 2>&1
    ```
7. 可以自己觸發bash看看
![image](https://hackmd.io/_uploads/Sk2ihrgM1x.png)
因為有加上時間，也可看cron有沒有觸發(這邊是設置5分鐘)
![image](https://hackmd.io/_uploads/HkSORrxMkl.png)

如果以上執行都沒問題
就可以重啟Compute engine，連線到domain，看看浮動IP指向有沒有成功生效

### SSL憑證(Compute Engine)
[參考這篇](https://www.kjnotes.com/devtools/62)
幫服務免費申請SSL憑證，目前服務還是http
![image](https://hackmd.io/_uploads/SJuNLNgGye.png)

一樣按步驟來
1. 先安裝certbot
    ```baash=
    sudo apt-get install certbot python3-certbot-apache -y
    ```
    ![image](https://hackmd.io/_uploads/HyMyYwlMJx.png)
2. 安裝好certbot，就可以申請SSL了，輸入指令
要寫上==自己的email==和換上剛剛申請的==DuckDNS的domain==
    ```bash=
    sudo certbot --apache --email yourEmail@gmail.com --agree-tos -d yourDomain.duckdns.org
    ```
    會先問說要不要分享Email，就依需求選擇
    ![image](https://hackmd.io/_uploads/H1G4iPxGJe.png)
    再來會問需不需要redirect Http到Https，我是輸入2繼續，確定就會往下執行完成
    ![image](https://hackmd.io/_uploads/Sy4y2wlzJl.png)
    到這邊就申請完成了
3. 完成之後就可以檢查看看能不能連上 ==https:/\/yourDomain.duckdns.org== 的網域了
然後可以檢查稍早做conf設定的資料夾內，應該會出現新的ssl設置，到這邊就完成了
![image](https://hackmd.io/_uploads/rJqNTPlz1g.png)
![image](https://hackmd.io/_uploads/BJ-jaPefkl.png)
連上了

不過要注意的是，免費SSL效期只有三個月，如果想要避免重複上述動作，應該就是要另外寫個bash來自動化?這部分我就不太確定，效期可以從剛剛申請完成提供的測試網址看到
![image](https://hackmd.io/_uploads/BJ5zeOxzJg.png)
![image](https://hackmd.io/_uploads/HJ6PlOgMkg.png)
或是直接在網頁上看憑證也可以
![image](https://hackmd.io/_uploads/Bkmy-dgzye.png)

### 靜態IP
回到GCP，可以從這邊看到目前使用中的IP
![image](https://hackmd.io/_uploads/SyG7GOgzke.png)

可以看到臨時對外IP
![image](https://hackmd.io/_uploads/rkRUzugGye.png)

點右邊三個點就可以看到==升級為靜態IP==
![image](https://hackmd.io/_uploads/SypazOlM1l.png)

輸入名稱，確認就可以看到轉為靜態IP
![image](https://hackmd.io/_uploads/rJne4uxGJx.png =40%x)
![image](https://hackmd.io/_uploads/Sku4QOez1g.png)

### SSL憑證(Load Balancer)
接下來要講的是由GCP託管的SSL
概念如下
![image](https://hackmd.io/_uploads/S1Ow-tgf1g.png)
▲這是之前設置的結構，每個compute engine都需要各自申請設置憑證，針對VM的憑證，除了憑證維護、更新繁瑣外，都是要走到GCP內才會經過SSL驗證

所以接下來要做的就是改為憑證交由Google託管，放在Load balancer層，請求可以在外層就被驗證，也可以維護單一SSL就好，如下▼
![image](https://hackmd.io/_uploads/H1UnQtlfJl.png)

可以看到目前憑證還是主機憑證
![image](https://hackmd.io/_uploads/r1BnEtgzkg.png =70%x)
Load balancer是基於==執行個體群組==
會把幾個VM做成群組這樣才能load balance
就算只有單一VM也要多包一層執行個體群組
接下來流程就是: 
->==把要執行的VM instance包成群組==
->==新增Load Balancer和Load Balancer層的SSL==
->==DNS解析到LB層的IP==
->==停用VM層的SSL==
就直接開始
1. 先用[快照](###快照)做個簡單備份
2. 建立一個==執行個體群組==
![image](https://hackmd.io/_uploads/rJbSIYeMJe.png =30%x)
![image](https://hackmd.io/_uploads/ryn9IFeG1e.png =70%x)
3. 這邊要自定義Load Balancer，選非代管群組
<font style='color:red;'>這邊位置區域要選和vm服務器相同，不然執行個體不會出現選項</font>
![image](https://hackmd.io/_uploads/ByoUCKgGJl.png)
4. 通訊埠對應就新增==http==、==80==，代表把連入流量導向到底下instance的80 port
![image](https://hackmd.io/_uploads/BJq4k9ez1g.png)
5. 好了就直接建立
![image](https://hackmd.io/_uploads/HkD5Jcezyg.png)
6. 再來就是建立Load Balancer和Load Balancer層的SSL
![image](https://hackmd.io/_uploads/HkZrg5lMyx.png)
![image](https://hackmd.io/_uploads/S1IkZ5xGyl.png =70%x)
依序選擇==應用程式負載平衡==>==公開(外部)==>==全域==>==全域==
7. 接下來設定前後端，可以簡單理解為:
    ==前端==: client連線到GCP Load Balancer的方式
    ==後端==: Load Balancer連線到Compute Engine instance的方式
    前端協定選HTTPS，就是說client要用https連線到Load Balancer
![image](https://hackmd.io/_uploads/ByUxE5xfJg.png)
8. 建立IP位址，新預留一個靜態IP
![image](https://hackmd.io/_uploads/r1Ow4qgzyl.png =40%x)
9. 建立新憑證，這邊選google代管，然後輸入自己的==domain==，前端到這邊結束
![image](https://hackmd.io/_uploads/rJNjV5gzJe.png =60%x)
![image](https://hackmd.io/_uploads/rJnV7qez1l.png =50%x)
10. 再來建立後端服務
![image](https://hackmd.io/_uploads/BJRtHqlGke.png =60%x)
==執行個體群組選剛剛建的那個==
然後Load Balancer連到VM的方式就走http就好，SSL會做在Load Balancer層前端
![image](https://hackmd.io/_uploads/rJy4wceMkg.png =60%x)
==設定健康檢查==
![image](https://hackmd.io/_uploads/BJHDw9xG1g.png =60%x)
==把Log打開==
![image](https://hackmd.io/_uploads/SJzTwclz1x.png =60%x)
==這裡也打勾，好了就建立==
![image](https://hackmd.io/_uploads/H1gOOqxMkg.png =60%x)
11. 後端服務完成就可以看到轉送服務也打勾了，這裡不用做任何動作，直接建立
![image](https://hackmd.io/_uploads/BkATdcxGkl.png)
12. 建立完成點進去就可以看到相關配置和IP
![image](https://hackmd.io/_uploads/HJWl5qxGyl.png)
這就是Load Balancer對外的IP，但現在應該還是連不上的
![image](https://hackmd.io/_uploads/rJcf9cezkg.png =90%x)
點開憑證可以看到，憑證還在路上，這部分可能會需要等好一陣子?先處理其他配置
![image](https://hackmd.io/_uploads/rJzQj5eGJg.png =70%x)
13. 把DNS解析改成Load Balancer的IP
![image](https://hackmd.io/_uploads/BJIaC5gMyl.png)
14. 進入服務器把最早配置在VM內的SSL副檔名直接改 ==.bak==讓它失效，然後重啟apache2
![image](https://hackmd.io/_uploads/rk6GA5xfJg.png)
15. 要記得把之前布置的cron任務停掉，不然DNS解析IP會跑掉，因為現在希望是解析到LB的IP不是VM的IP，我是直接註解掉
![image](https://hackmd.io/_uploads/HyUREilG1e.png =70%x)

接下來就是只能等LB的SSL生效了，包含DNS更改解析IP，最久可能要等個2天...
可以用[https://dnschecker.org/](https://dnschecker.org/)查全球同步，但還是只能等...

---
過了一天回來看，GCP這邊就顯示處理好了
![image](https://hackmd.io/_uploads/BJV0SnWM1l.png)

接下來就可以連線看看
![image](https://hackmd.io/_uploads/Sk_U7pbfJg.png =80%x)

顯示重新導向問題，檢查一下conf檔，==/etc/apache2/sites-available/testweb.com.conf==
![image](https://hackmd.io/_uploads/BklxETWM1g.png =80%x)
發現這段，==sudo vim==編輯，把這段註解掉
![image](https://hackmd.io/_uploads/HJPQB6bG1l.png =80%x)
註解完重啟apache2
```bash=
sudo systemctl reload apache2
```

重啟完應該就可以連上了
![image](https://hackmd.io/_uploads/H1LkUpbMkx.png)
可以看下SSL，現在就變成是Google核發的憑證，走Load Balancer進服務的方式
不過因為是用免費domain，所以google核發的也是==letsencrypt==
只能從核發時間確認是不是新的憑證
![image](https://hackmd.io/_uploads/r1geT0WGke.png =60%x)
不然正常應該會顯示類似這樣(==GTS==)
![image](https://hackmd.io/_uploads/H1zNT0Wfke.png)



### 快照
就想像是一個快速備份的方式，備份方式是增量不是全量，所以不要隨便刪除舊快照
![image](https://hackmd.io/_uploads/ryr6KYxfkx.png =30%x)

這邊是簡單快速備份，就選即時快照就好
![image](https://hackmd.io/_uploads/rJJ_9tlGkg.png =70%x)

好了就直接建立，就可以了
![image](https://hackmd.io/_uploads/SknT9Yxzyg.png)

## 建構CI/CD完整服務
--- 
▼▼▼▼▼▼▼▼
[**<font style='color:red; font-size:30px;'>強烈警告</font>**](#強烈警告)
▲▲▲▲▲▲▲▲

--- 
### 服務架構
這邊就先把舊服務停用移除了，雖然是免費試用的額度但還是不想浪費，
也不要多留個有風險的漏洞在那邊
靜態IP和Load Balancer也都清除，就整個重頭開始
理想架構如下
![image](https://hackmd.io/_uploads/HJAG6sGB1x.png)

主要分為兩個部分:
1. 開一個單一Compute Engine，用docker啟動一個Jenkins服務，做CI的部分，限制連入IP
2. 利用GKE做CD，自動部屬相關服務，服務全部都走ClusterIP內部調用
連入只能透過LoadBalancer，防火牆另外處理(練習建議針對特定IP開放就好)
LoadBalancer指向Ingress，SSL做在Ingress，透過路由往下到服務內
服務間透過ClusterIP相互溝通

這是到目前為止進度
:::success 
√ 專案commit, push上Repository 
:::
:::danger 
× Repository自動觸發Jenkins CI，自動打包images上Dockerhub
:::
:::danger 
× CI觸發CD，讓GKE自動更新部署
:::
:::danger 
× GKE部屬完成確定功能正常
:::
:::danger 
× 對外服務確定網路安全或流量問題
:::

--- 
▼▼▼▼▼▼▼▼
[**<font style='color:red; font-size:30px;'>強烈警告</font>**](#強烈警告)
▲▲▲▲▲▲▲▲

--- 

然後專案的資源需求我是依靠本地練習時使用docker-desktop的資源紀錄來看
### Jenkins服務
就先做jenkins server吧
決定是用E2-medium，作業系統一樣Ubuntu吧，順便練習Linux

![image](https://hackmd.io/_uploads/H1lytBQMJx.png)

就建起來
![image](https://hackmd.io/_uploads/SkfDlD4fJl.png)

一樣先==sudo apt update==更新
```bash=
sudo apt update
```
然後就開始安裝需要的東西吧
先裝一些常用工具
```bash=
sudo apt install apt-transport-https ca-certificates curl software-properties-common
```
![image](https://hackmd.io/_uploads/H1U7Lw4zJl.png)

接下來是安裝docker
[參考這裡](https://medium.com/@jieshiun/%E5%A6%82%E4%BD%95%E5%9C%A8-ubuntu-20-04-%E5%AE%89%E8%A3%9D-docker-%E8%88%87-docker-compose-27a88b3d746b)
先下載docker的GPG密鑰
```bash=
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
```

添加軟體源
```bash=
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
```

然後就安裝docker
```bash=
sudo apt install docker-ce docker-ce-cli containerd.io -y
```
docker-compose不能用apt裝，因為apt庫版本太舊，要用curl裝
```bash=
#安裝docker-compose
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/bin/docker-compose

#更新執行權限
sudo chmod +x /usr/bin/docker-compose
```

安裝完就可以==docker version==看看有沒有安裝成功
應該就可以看到docker版本了，但這邊應該會出現提示說權限不足
![image](https://hackmd.io/_uploads/r1PBVOEz1x.png)
gcp登入的用戶是沒有docker group的，這邊有兩種方式，一種是每個指令都用sudo，一種就是把用戶加docker group
```bash=
sudo usermod -aG docker $USER
```
加完之後重啟終端才會生效
![image](https://hackmd.io/_uploads/S1mlU_4fJx.png)

這樣就可以不加sudo了
![image](https://hackmd.io/_uploads/H1E0LO4fyg.png =50%x)

到這邊docker就安裝完了，接下來就是把先前[配置](https://hackmd.io/SHki-PsHQayuExX-qSXmbQ)做好的docekrfile和docker-compose上傳到Server，直接用建構好的配置來啟動容器，一樣先綁定filezilla的ssh方便之後操作
![image](https://hackmd.io/_uploads/r1H7yFNM1g.png)
然後預設用戶不是root，所以是沒有資料夾存取權限的，
這邊看到默認目標資料夾 ==(/var/local)== 存取權限是==staff group==
![image](https://hackmd.io/_uploads/r14xPK4zJl.png)
這邊就把本人加到staff組
```bash=
sudo usermod -aG staff your_user
```
偷懶也可以直接開==777==
如果遇到權限問題也可以善用filezilla會顯示每個文件權限
![image](https://hackmd.io/_uploads/HyivhFVMJl.png =70%x)

然後這邊可以直接把dynamic IP生成static IP
用static IP連線，因為後面就直接常態使用了
![image](https://hackmd.io/_uploads/HJiy0K4fJg.png)

連線把要建構的檔案放上Server
![image](https://hackmd.io/_uploads/ryDxZYNGJx.png =70%x)
就都和上面練習差不多
確定放上服務器
![image](https://hackmd.io/_uploads/rJTMcK4fke.png =70%x)
![image](https://hackmd.io/_uploads/rJ8I9K4zke.png)

接下來就運行docker-compose，確認是不是有在運行
```bash=
docker-compose up --build -d
```
![image](https://hackmd.io/_uploads/BJUlv5Vzyg.png)

確定成功跑在8080port，但實際測試會發現連不上，原因是因為GCP防火牆會擋掉外部端口連線
但這邊先不管，因為要做成https，先做SSL憑證，後面再處理防火牆
![image](https://hackmd.io/_uploads/BJrRDc4Mkx.png)

DuckDNS加一個domain，解析到VM的外部IP
![image](https://hackmd.io/_uploads/BJ04ceiGJx.png)
然後一樣先安裝apache2，==sudo apt install apache2 -y==
接下來就參照[免費SSL配置](###SSL憑證(Compute-Engine))
過程省略
![image](https://hackmd.io/_uploads/BkSyAbszJx.png)
申請好之後，會發現一個問題就是HTTPS連線是443 port進線轉默認80 port(目前是apache2)
也因為這邊沒有走Load Balancer層，不能用執行個體群組導向其他port
但現在要使用的服務在8080 port上，所以這邊要做反向代理服務把默認80轉到8080上
一般可以用==nginx==或是==apache==，這邊就用apache2繼續吧
先確保相關代理模組有安裝，安裝完重啟apache2
```bash=
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo systemctl restart apache2
```
![image](https://hackmd.io/_uploads/Bkta3Wof1x.png)

再來就是要修改apache2的SSL連線配置
![image](https://hackmd.io/_uploads/B1Eg4Mozyx.png)
==000-default-le-ssl.conf==是監聽443端口
==000-default.conf==是監聽80端口
```bash=
#就打開編輯配置
sudo nano 000-default-le-ssl.conf
```
打開可以看到監聽端口，配置ProxyPass就是反向代理服務
![image](https://hackmd.io/_uploads/SJZVHziz1g.png =90%x)
更新之後，可以==sudo apach2ctl configtest==測試
通過就會顯示==Syntax OK==，就重啟
![image](https://hackmd.io/_uploads/BJktwzoMkl.png)
重啟之後反向代理就會生效，就可以連上(8080 port)了
![image](https://hackmd.io/_uploads/B1Vg_GjMyx.png)

### 防火牆配置
先來設定防火牆，因為目前的配置應該是完全公開域名，沒有任何限制IP
但希望改成只有特定IP能連線
私有雲網路找到防火牆
![image](https://hackmd.io/_uploads/BkD46zoG1x.png =50%x)
可以看到這邊已經有一些默認規則了, 
要注意的是==目標==就是會套用到該規則的服務標籤，==0.0.0.0/0==就是允許所有外部IP連接
![image](https://hackmd.io/_uploads/ryeA6zoG1e.png)
可以比對instance的設定
![image](https://hackmd.io/_uploads/rJd8nzoGyg.png =80%x)
:::info
這邊只希望對特定IP開放，又不想去修改默認防火牆，這邊就不套默認規則
自己給instance一個標籤，再針對這個標籤去新增防火牆，只針對想開放的對外做開放
:::
把instance默認防火牆拔掉，自己新增一個標籤
![image](https://hackmd.io/_uploads/r11b-mizJl.png =80%x)
拔掉之後可以連到domain試試，應該就會變成連不上了
1. 接下來先處理遠端FileZilla SSH(SFTP)連線到VM的防火牆
就開一個新的防火牆，流量==輸入==表示外部連入服務器
重點是目標標記設成針對<font style='color:red;'>剛剛創建的標籤</font>
來源設==要放行的連線IP==，port就==TCP:22==(ssh)
![image](https://hackmd.io/_uploads/HyjBrmozyl.png =60%x)
好了就建立，建完測試FileZilla應該就可以正常連上了
![image](https://hackmd.io/_uploads/HkjtO7iGye.png)
2. 再來是做特定IP用HTTPS連線的防火牆
一樣新增防火牆，流量==輸入==
目標標記設成針對<font style='color:red;'>剛剛創建的標籤</font>
來源設==要放行的連線IP==，port就==TCP:443==(https)
![image](https://hackmd.io/_uploads/ByuFqmoMkg.png =60%x)
一樣好了建立，實際測試jenkins UI應該就可以連上了
![image](https://hackmd.io/_uploads/H1iCsXjMkl.png)

:::success
這邊總共加了兩個防火牆
1. 外部特定IP走HTTPS連線到VM
2. 外部特定IP走SSH連線到VM

![image](https://hackmd.io/_uploads/H1KdjQjGkx.png)
:::

### Jenkins防火牆番外篇(github webhook)
因為instance防火牆只針對特定IP開放，但jenkins要綁定Github webhook
所以==防火牆==要針對Github的請求IP做開放，==看hooks==
[官方文件](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/about-githubs-ip-addresses)
[官方IP文件](https://api.github.com/meta)
![image](https://hackmd.io/_uploads/SJLPq3GXyl.png)
加到防火牆，ipv4和ipv6都加
![image](https://hackmd.io/_uploads/ry3hMpzmyg.png)

可以從Github的Recent Deliveries看觸發紀錄
![image](https://hackmd.io/_uploads/HJknBafmJe.png)

也可以從GCP log確定，可以看到請求從剛剛新增放行的IP過來
![image](https://hackmd.io/_uploads/SkuvmpzQ1e.png)

然後就一樣確保CI流程(綁webhook觸發)，image可以成功打包更新到repository
![image](https://hackmd.io/_uploads/HJQoiyQXye.png)
![image](https://hackmd.io/_uploads/HyXyn1XXJx.png)

這樣Jenkins端的服務就全部完成了
:::success
全部總共加了三個防火牆
1. 外部特定IP走HTTPS連線到VM(包含Github webhook ipv4 IP)
2. 外部特定IP走SSH連線到VM
2. Github webhook IP走SSH連線到VM
:::

這是到目前為止進度
:::success 
√ 專案commit, push上Repository 
:::
:::success 
√ Repository自動觸發Jenkins CI，自動打包images上Dockerhub
:::
:::danger 
× CI觸發CD，讓GKE自動更新部署
:::
:::danger 
× GKE部屬完成確定功能正常
:::
:::danger 
× 對外服務確定網路安全或流量問題
:::

### GKE(Google Kubernetes Engine)
目前已經完成CI的部分，image上dockerhub了，建構k8s服務的yml先前[本地部屬練習](https://hackmd.io/@S1MNxjTORYSfAfivxMlEQw/r16KxTmkkx)也做完了
CD的部屬，在我的理解可以分為兩種方式:
1. 統一由Jenkins的pipeline來做操作，原理就和[本地部屬練習](https://hackmd.io/@S1MNxjTORYSfAfivxMlEQw/r16KxTmkkx)一樣，差別只在要確保jenkins內部可以調用操作GKE，畢竟服務是要運行在GKE上的，不是透過相同的本地k8s
2.  CI和CD拆分，jenkins就只負責CI，把專案打包成images推到repository
CD只要專心做好從repository拉images部屬的動作，剩下就是解決CI後的自動通知觸發
(可能用GitOps或是Google Cloud 的 Pub/Sub)

接下來做CD，就按順序來:
1. 先進到Google Kubernetes頁面，啟用GKE服務
![image](https://hackmd.io/_uploads/SkYFTIB4kl.png =40%x)
![image](https://hackmd.io/_uploads/SkWIaLSV1g.png =60%x)
2. 先建立一個cluster，叢集位置可以選和instance服務一樣
![image](https://hackmd.io/_uploads/By_7b-X7yg.png =60%x)
3. 就給個名稱，zone我是選和CI服務相同區域但不確定有沒有差別
剩下都不用改，就直接建立
![image](https://hackmd.io/_uploads/BJ48NwSN1l.png)
4. 建構需要一點時間，點擊可以看到
![image](https://hackmd.io/_uploads/B17q8DSEJe.png =70%x)
5. 建構完成之後可以開啟右上角==Cloud Shell終端==
![image](https://hackmd.io/_uploads/H1is6PrNkl.png)
6. 開啟後要點▼選正確專案(應該也是只有一個能選就是了)
![image](https://hackmd.io/_uploads/SkRqB_AE1x.png =70%x)
檢查專案的指令: ==gcloud config get-value project==
![image](https://hackmd.io/_uploads/HyWpjKR41e.png)
檢查叢集的指令: ==gcloud container clusters list==
![image](https://hackmd.io/_uploads/B17y2YRVJg.png)
7. 切換到專案後，要配置系統預設zone，方便後續指令可以省略相關指令
這邊我直接按照叢集的zone做配置
==gcloud config set compute/zone asia-east1==
配置完檢查相關系統設定，確認有project和zone
==gcloud config list==
![image](https://hackmd.io/_uploads/rk_kxc0Eyl.png)
8. 接下來應該就是用kubectl去做後續操作，但會發現kubectl指令錯誤，類似這樣
![image](https://hackmd.io/_uploads/r1Gb6F0EJx.png)
原因是叢集還沒做GKE驗證，做了才能連結kubectl和叢集
指令: ==gcloud container clusters get-credentials <叢集名>==
因為前面有配置系統默認project和zone所以這邊指令比較簡單
不然都要加上指定zone和project
![image](https://hackmd.io/_uploads/rJfIW9A4kx.png)
驗證連結後就可以使用Kubectl指令了
9. 再來就可以開始建構需要的服務了，先前已經有做好建構服務的yml文件，這邊就傳上終端運行
點擊終端右上角==三點圖示==，選上傳，然後就把做好的yml傳上去
![image](https://hackmd.io/_uploads/SySbNcREye.png =60%x)
![image](https://hackmd.io/_uploads/HkEni9A4Je.png =40%x)
![image](https://hackmd.io/_uploads/ryUy2qREyg.png)
10. 然後就按照之前[本地測試部屬的流程](https://hackmd.io/@S1MNxjTORYSfAfivxMlEQw/r16KxTmkkx#%E5%AE%8C%E6%95%B4%E5%BB%BA%E6%A7%8B)去apply
本地測試已經排除大部分問題了，這邊就是剩下一些小問題做個紀錄
* ==redis==是用官方images沒什麼問題
* ==mssql==要注意密碼規範
* ==mssql==持久化的部分GCP不能用hostPath，要選一個靜態磁碟(我直接放在Jenkins服務器上)
![image](https://hackmd.io/_uploads/BJ5NDnANyx.png =60%x)
* ==mssql==會遇到調用init腳本權限不足問題，要在yml針對執行權限加上配置
![image](https://hackmd.io/_uploads/Syxsw3CNkl.png =50%x)
* ==erp-base==沒什麼問題，要注意啟動log有沒有系統權限，初次啟動可能會抓不到，重啟即可
* ==erp-view==要配置外部連入，比較複雜，除了原先的yml，
要多做一個Ingress的yml用來轉發外部連線到前端port跟處理SSL憑證，這邊就按順序來
11. <b>Ingress Controller</b>:
[關於Ingress說明，講蠻好的](https://ithelp.ithome.com.tw/articles/10272717?sc=pt)，有兩種方式做
* Nginx Ingress搭配cert-manager做SSL證書，但就是要手動做配置
* GCE Ingress Controller整合GTS證書<font style='color:red;'>(既然都要做在GCP上了就選這個方法)</font>

▼最終版的erp-view.yml
```yaml=
apiVersion: apps/v1
kind: Deployment
metadata:
  name: erp-view
  labels:
    app: erp-view
spec: 
  replicas: 1
  selector:
    matchLabels:
      app: erp-view
  template:
    metadata:
      labels:
        app: erp-view
    spec:
      imagePullSecrets:
        - name: dockerhub
      containers:
      - name: erp-view
        image: ryanimay840121/erp-view:latest
        imagePullPolicy: Always
        ports:
          - containerPort: 8082
          
---
apiVersion: v1
kind: Service
metadata:
  name: erp-view
spec:
  type: ClusterIP  # 使用 ClusterIP，外部流量由ingress統一處理轉發
  ports:
    - port: 80   # 暴露80端口，就不用另外帶port
      targetPort: 8082
  selector:
    app: erp-view
```
▼新增的ingress.yml
```yaml=
# Google Managed Certificates管理證書
apiVersion: networking.gke.io/v1
kind: ManagedCertificate
metadata:
  name: gts-managed-cert
spec:
  domains:
    - erppp.duckdns.org
    
---
# GCE Ingress Controller
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: erp-ingress
  annotations:
    kubernetes.io/ingress.class: "gce" # 這邊特別注意
    networking.gke.io/managed-certificates: gts-managed-cert  # 將 GTS 憑證綁定
spec:
  ingressClassName: gce #為了版本兼容，不寫也可以正常執行但kubectl指令都會顯示CLASS<none>
  # defaultBackend: # 可以設定預設，如果沒有匹配路由就轉發到這
    # service:
      # name: erp-view
      # port:
        # number: 80
  rules:
    - host: erppp.duckdns.org # 匹配路由轉發到這
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: erp-view
                port:
                  number: 80
```
<font style='color:red;'>特別注意`kubernetes.io/ingress.class` 雖然會提示K8s捨棄這種用法改用**ingressClassName**，但GKE不支持，所以還是要用這個寫法，這邊兩種都寫是為了兼容</font>
![image](https://hackmd.io/_uploads/S1yZcylBke.png)
[官方文件說明](https://cloud.google.com/kubernetes-engine/docs/how-to/load-balance-ingress)
<font style='color:red;'>然後不寫**defaultBackend**是因為希望只有匹配domain才能連入，等於也不能走外部IP連線</font>

做完一樣上傳到Cloud終端，然後apply運行
最終結果應該會長這樣
![image](https://hackmd.io/_uploads/rkORn3yr1g.png)
這邊都是直接用cloud terminal指令去操作，GKE的UI介面看看就好
全部服務都是僅限集群內部調用
可以從介面確認Ingress創建狀況
==這是有寫**defaultBackend**，可以看到有匹配規則是`IP/*`==
![image](https://hackmd.io/_uploads/ry0URkgBJe.png)
==這是沒寫**defaultBackend**，可以看到有匹配規則只有`domain/`==
![image](https://hackmd.io/_uploads/ByXFLvGH1l.png)
也可以==kubectl get ingress==確認有沒有新增成功
![image](https://hackmd.io/_uploads/Hy0Upygr1g.png)
可以看到一組IP，就是對外IP，拿去<font style='color:red;'>做DNS解析</font>，DNS這邊一樣走==Duck DNS==
然後再來就只能等證書了，==kubectl describe managedcertificate gts-managed-cert==查結果
![image](https://hackmd.io/_uploads/HJqTaJlrke.png)
這是通過之後的終端顯示
![image](https://hackmd.io/_uploads/rJSIZegH1g.png)
然後看到網路服務>負載平衡，可以看到自動創建了一個LoadBalancer
![image](https://hackmd.io/_uploads/HJnnkKzH1g.png)

--- 
▼▼▼▼▼▼▼▼
[**<font style='color:red; font-size:30px;'>強烈警告</font>**](#強烈警告)
▲▲▲▲▲▲▲▲

--- 
進去會發現**前後端服務都會分別有兩個**
前端原因是因為
![image](https://hackmd.io/_uploads/HJ8VeKGH1g.png)
後端除了導向到ingress的服務，還有自動創建一個**default-http-backend**
原因是因為ingress沒有配置defaultBackend，LB會自動把沒匹配到的請求導向到一個用於處理「未找到匹配路徑」的預設HTTP錯誤處理器。
![image](https://hackmd.io/_uploads/rJujxYGrJl.png)

證書的部分點進去可以看到相關配置和證書狀態
![image](https://hackmd.io/_uploads/HJy2kxeHJx.png)

--- 
▼▼▼▼▼▼▼▼
[**<font style='color:red; font-size:30px;'>強烈警告</font>**](#強烈警告)
▲▲▲▲▲▲▲▲

--- 
通過就可以連線了~~然後就可以測試看看功能和ClusterIP內部調用有沒有什麼問題
![image](https://hackmd.io/_uploads/r1dYJelrkg.png)

然後就發現websocket連線爆炸...因為現在只有開ClusterIP，沒有對外的port了，和測試時不同
:::info
Websocket問題原因很複雜，總結就是
1. 前端發起WS連線是使用SockJS，所以不支持`ws://`或`wss://`
2. 前端有配置GCE ingress controller和SSL證書，走HTTPS連線
因為這樣導致前端頁面只能用HTTPS開啟，連帶原先測試時可以用http進行websocket連線，現在不行，只能走`https://domain`，一定要經過ingress，剩下有兩種方法到後端:
    * 寫`https://domain/特定url`，<font style='color:red;'>由ingress轉發到後端</font>，不走原先的nginx
    * 一樣寫`https://domain`，一樣ingress到nginx，再<font style='color:red;'>由nginx轉發到後端</font>
    
![image](https://hackmd.io/_uploads/BJYw7D-SJe.png)
:::
這邊就統一都走nginx轉發的方式，這樣nginx也不用修改，也不用另外配置ingress，按順序來:
1. 改websocket連線的方式，直接走`https://domain`
![image](https://hackmd.io/_uploads/SJrlSLbryl.png)
2. 改完一樣重新打包image上dockerhub，再重新部屬應該就可以了

Ingress的Log可以看到，ws連線成功
![image](https://hackmd.io/_uploads/Bk9BBvbH1x.png)

--- 
▼▼▼▼▼▼▼▼
[**<font style='color:red; font-size:30px;'>強烈警告</font>**](#強烈警告)
▲▲▲▲▲▲▲▲

--- 
這是到目前為止進度
:::success 
√ 專案commit, push上Repository 
:::
:::success 
√ Repository自動觸發Jenkins CI，自動打包images上Dockerhub
:::
:::danger 
× CI觸發CD，讓GKE自動更新部署
:::
:::success 
√ GKE部屬完成確定功能正常
:::
:::danger 
× 對外服務確定網路安全或流量問題
:::
關於自動觸發CD，相對沒有這麼急迫，既然現在連線可以對外，就趕快處理防火牆吧
我不想收到莫名其妙的帳單

## <font style='color:red;'>強烈警告</font>
:::danger
先快速感受一下，來自這個世界滿滿的善意，各種kill各種攻擊，所以能擋就擋吧
強烈建議練習的話開自己需要連線的IP就好，其他全部都要擋掉，認真看完底下說明
![image](https://hackmd.io/_uploads/rJDcHozH1x.png)
:::

### 關於網路安全性(防火牆/Cloud Armor)
既然現在服務可以讓外部連上，那就要開始擔心安全性和風險，
包含資料隱私或流量攻擊(DDos、Spam...)的防護
雖然目前是試用帳戶，沒開通完整帳戶
就算免費流量用完也不會被多扣，但還是要了解一下相關知識
然後如果要真的夠穩，不怕爆流量，最好還是用VPS，流量超過就終止服務(GCP只能發通知...)
本來就也只是為了練習，==重點還是使用完要記得關掉==
不然大部分雲服務都只能做到發送通知，但錢包還在繼續跳
[前幾天才看到的被攻擊經驗談](https://www.facebook.com/share/1TB5zrvi8j/)
[求退費經驗談](https://medium.com/%E7%A8%8B%E5%BC%8F%E4%B9%BE%E8%B2%A8/gcp-%E9%80%80%E8%B2%BB-%E6%9C%8D%E5%8B%99%E5%BF%98%E8%A8%98%E9%97%9C%E9%96%89-a7db63e51186)
==!!這都還只是流量大的問題，重點是還會有像上面範例那種奇怪的指令請求!!==
關於請求進GCP的完整流程，上面簡單練習只有
做到==DNS -> (CDN) -> Load Balancer -> 服務==
其中Load Balancer自帶Cloud CDN(靜態資源緩存，可選)，這邊就不多做配置
後續最好就是要加上連線到服務的==Cloud Armor==，
變成==DNS -> (CDN) -> Load Balancer -> Cloud Armor -> 服務==，可以<font style='color:red;'>稍微</font>做到限制防範流量
![image](https://hackmd.io/_uploads/ByFQT8_GJl.png)

但要注意，
<font style='color:red;'>有時候人家的請求量甚至沒有達到需要防範攻擊的標準，但問題是你的錢包先沒錢了</font>
![image](https://hackmd.io/_uploads/S1azMPOMJg.png)

:::success
大致理解一下就好，這邊預計也只開特定IP訪問權限
:::

先前配置Jenkins時已經順帶做好相關防火牆
接下來主要就是針對==全域的防火牆==和前端服務去設置
前端服務因為是走GKE LoadBalancer不是走ComputeEngine，所以要做限制要從==CloudArmor==，接下來會提到
需要做的有幾個部分:
1. 到==防火牆==，<font style='color:red;'>default-allow-ssh</font>的部分原先是對外所有IP都打開
![image](https://hackmd.io/_uploads/BJDy1atz1x.png)
這邊改成只針對<font style='color:red;'>35.235.240.0/20</font>，就是只針對GCP開放用SSH連線
![image](https://hackmd.io/_uploads/SJ65ahtMkg.png)
    :::info
    做完這邊之後，所有的instance都只能透過GCP去做SSH連線，外部要連都要另外放行
    :::
2. 再來就是要做==Cloud Armor==，用意就是可以
限制經過<font style='color:red;'>Load Balancer層</font>(基於)往服務的IP(黑/白名單)或流量速率
點進頁面可以看到有一條預設政策
![image](https://hackmd.io/_uploads/Bk7g4hWX1g.png)
3. 點擊就可以看到這個政策底下的規則和適用的服務，預設兩個，要簡單限制就是直接這邊做修改
![image](https://hackmd.io/_uploads/SJR4ta-m1g.png)
4. 舉例，編輯節流
![image](https://hackmd.io/_uploads/rkTnYpZ71x.png)
規則類型創建後不可更改，但是可以更新參數，也可以設定受限後返回結果
![image](https://hackmd.io/_uploads/S1BWcaWQkg.png)
5. 儲存後，<font style='color:red;'>通常要過幾分鐘才會生效</font>
實際測試多次刷新頁面，就可以看到超過頻率限制被擋下
這樣就可以針對最基本的流量攻擊做個限制
![image](https://hackmd.io/_uploads/BJGpNjfmJe.png)
6. 也可以對LB進來的請求做IP限制
(不然正常是不能針對LB做防火牆，一般防火牆是只針對instance)
==新開一個規則，僅限特定IP放行==
:::danger
**特別注意!! Cloud Armor的規則，不是一層一層篩選
只要匹配到相符的規則就只有放行(ACCEPT)或拒絕(DENY)
所以假設優先級0是放行所有IP，那優先級後面的所有規則都不會生效，因為已經被放行了
不管是限流還是拒絕所有IP都是一樣**
![image](https://hackmd.io/_uploads/Hkso8qGBJe.png)
**我目前就只開放自己的IP，拒絕其他所有IP**
:::
7. 點擊目標可以看到目前有套用到這個限制規則的LB服務，把有開的服務都加一加吧
![image](https://hackmd.io/_uploads/H1mld9zByg.png)
8. 到這裡就可以對陌生外部請求有基本的防範了，只要不是名單內IP，請求都會直接返回403
![image](https://hackmd.io/_uploads/H1b7ghzHye.png)
:::info
但說到底，網頁本身總不可能永遠都只有自己使用，總是要對外的
防範的基礎主要還是在服務本身，要想辦法自己避免各種注入攻擊或怪怪的操作
像我練習時一開始沒注意到對外服務會被亂帶指令的問題，瘋狂被攻擊了快一個月
也是因為程式本身有做好(大概?)所以沒遇到什麼問題
:::

--- 
<font style='color:red;'>**※**</font> 如果有遇到instance被健康檢查會失敗的原因，可能是因為沒有開放對應埠，這邊就新增一個防火牆針對健康檢查放行，標記就是剛剛新增的標記，來源設定==35.191.0.0/16==和==130.211.0.0/22==，這是GCP內部發起請求的IP，開放埠就是看健康檢查是要檢查哪裡，好了就儲存
[▼官方說明]()
![image](https://hackmd.io/_uploads/ryfxe_781x.png)

![image](https://hackmd.io/_uploads/SkibEsW7Je.png =80%x)
再回Load Balancer，就可以看到健康檢查通過了
![image](https://hackmd.io/_uploads/rk3ySsWXkg.png)

到這邊關於防火牆和CloudArmor也差不多了，這是到目前為止進度
:::success 
√ 專案commit, push上Repository 
:::
:::success 
√ Repository自動觸發Jenkins CI，自動打包images上Dockerhub
:::
:::danger 
× CI觸發CD，讓GKE自動更新部署
:::
:::success 
√ GKE部屬完成確定功能正常
:::
:::success 
√ 對外服務確定網路安全或流量問題
:::

最後就剩下把CI觸發CD串起來了

## 最後CI串CD
要讓CI/CD串接的部屬流程就會和上面手動部屬不太一樣
yml的部分不是手動放到環境中端執行，會改成和CI一樣放倉庫，要做大致有兩種方式:
* ==直接用Jenkins的pipeline去操作GKE，就像測試本地部屬時一樣==
* 綁GitOps工具(ArgoCD或FluxCD)，把yml配置放Git，CI做完工作之後去自動更新配置檔(更新版號)推上倉庫，利用webhook的方式，觸發GKE拉配置檔來部屬，[[參考](https://blog.csdn.net/djuyqnixvh/article/details/135096432?ops_request_misc=%257B%2522request%255Fid%2522%253A%252250ce3352b88a9ebef536c1268ddb9286%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=50ce3352b88a9ebef536c1268ddb9286&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~hot_rank-6-135096432-null-null.142^v100^control&utm_term=jenkins%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90%E7%89%88%E6%9C%AC%E5%8F%B7&spm=1018.2226.3001.4187)]

這邊走Jenkins統一調用的方式，要在Jenkins內操作GKE需要
* GCP拿service account金鑰(要確定有權限)
* GKE拿kubeconfig證書
* Jenkins安裝gcloud和kubectl用來操作
* Jenkins配置剛剛拿到的金鑰和證書

這樣就可以遠程調用了，就案順序來:
1. 先到服務帳戶，點帳戶的管理金鑰
![image](https://hackmd.io/_uploads/Bys13FPHJe.png)
![image](https://hackmd.io/_uploads/Sk4E3FvB1l.png)
2. 建立新的金鑰，格式選json，應該就會下載一個文件到本地，這就是GCP的金鑰
![image](https://hackmd.io/_uploads/HkSd2KDHJg.png)
![image](https://hackmd.io/_uploads/r1UK3KvHkl.png =60%x)
3. 金鑰處理好再來是GKE憑證，開啟終端進入要遠端調用的專案
輸入指令==gcloud container clusters get-gredentials 叢集名稱 --zone 叢集區域==
像這樣
![image](https://hackmd.io/_uploads/By-cTKwrkx.png =40%x)
![image](https://hackmd.io/_uploads/H1K3TKwrJx.png)
這樣系統就會創建~/.kube/config證書
4. 但接下來就會遇到一個問題，就是要把證書下載到本地，方式有很多種，cloud terminal也有提供UI操作下載
![image](https://hackmd.io/_uploads/HkYURYPHJe.png =50%x)
但打開會發現，找不到.kube資料夾，原因是因為.kube是因藏資料夾
這邊用最簡單的方式，直接指令複製到外層
![image](https://hackmd.io/_uploads/SJrekqwHJl.png)
這樣就可以直接用UI找到config文件下載到本地了
5. 再來就是要把下載的本地文件配置給Jenkins，先進入Jenkins服務器UI
==資訊主頁== > ==管理Jenkins== > ==Credentials== > ==+Add Credentials==
---
做到一半因為一些因素擱置了一陣子，GCP的免費試用沒了QQ，剩下就單純文字記錄，整體用GCP+GKE做CI/CD都可以了，剩下就是一些細節的微調:
1. 關於版號，一開始偷懶都用<font style='color:red;'>:lastest</font>，但造成後續部屬k8s的問題，因為版號沒有變動導致更新不生效，本地練習k8s手動去跑yml更新就可以了，但用GKE時不確定是不是有什麼緩存問題，手動刪除在重新更新也是沒有生效，這部分也沒解決，但重點還是版號區隔，簡單做的話預計是用時間戳或是git 