成本分析與 FinOps 建議
1️⃣ Delete unused reserved external IP addresses
在 Google Cloud 上,如果您保留了靜態 IP(Static IP 或稱外部 IP, External IP)位址,卻未將該位址指派給任一資源(例如 VM 執行個體或轉送規則),或是隨時間推移虛擬機器完成階段任務,但確沒有將之移除,這些「預留」的 IP,GCP 並不會幫你自動移除。而這些閒置 IP 的費率會高於使用中的靜態 IP,有點帶有逞罰計價的味道。這種浪費可能會隨時間推移變得非常顯著,特別是對於那些嚴重依賴靜態 IP 並且有大量使用的應用程式來說。
9.36 美元(0.013 x 24 x 30)是 Google 對未使用的靜態 IP 每月收取的費用(asia-east1),你可以找到多少的這類未使用的靜態 IP?
👎 壞消息是靜態或臨時 IP(IPv4)計費在 20240201 漲價了,漲幅高達 25%;IP 正式從免費到計價,再到漲價年代
📰 20240201 — BillingNews
Static and ephemeral IP addresses in use on standard VM instances will go from $.004 to$.005.
Static and ephemeral IP addresses in use on preemptible VM instances will go from $.002 to$.0025.
2️⃣ Clean up unattached and orphaned persistent disks
永久性磁碟若在建立時未掛接到虛擬機,或者虛擬機具有多個磁碟,並且一個或多個磁碟已分離,則這些永久性磁碟就是未使用(orphaned)或孤立(unattached)的磁碟,這些磁碟佔用空間的費用也是滿嚇人。
磁碟定價
每個 VM 至少會連接一個磁碟,且每個磁碟都會產生費用,且計價上是包含所有已使用和未使用的空間,如果申請 200 GB 磁碟,系統會向您收取整個磁碟空間的費用,直到釋出磁碟空間為止。
Persistent Disk 類型選擇
配置永久性磁碟時,您可以選擇以下磁碟類型(Storage options),從便宜至貴的介紹
標準型( pd-standard
)💰
- 以標準硬碟(HDD)作為支援,適用於主要使用 sequential I/Os 的大型資料處理工作負載
均衡型(pd-balanced
)💰💰
- 效能(
pd-ssd
) 永久性磁碟的替代方案並以固態硬碟(SSD)作為支援 - 性能與費用的平衡。對於大多數虛擬機器形式(非常大的磁碟類型除外),這些磁碟具有與 SSD 永久性磁碟相同的最大 IOPS,這種磁碟類型提供的效能適合大多數通用應用,價位介於標準永久性磁碟和效能(pd-ssd)永久性磁碟之間
效能(SSD)型(pd-ssd
)💰💰💰
- 以固態硬碟(SSD)作為支援,適用於需要比標準永久性磁碟更短延遲時間和更多 IOPS 的應用程式和高效能資料庫
- 專為單數位毫秒延遲而設計
極端型( pd-extreme
)💰💰💰💰
- 以固態硬碟(SSD)作為支援,為隨機存取工作負載和批量吞吐量提供始終如一的優越效能
- 專為高階資料庫工作負載而設計
- 允許您預配目標 IOPS
- 適用於有限數量的機器類型
磁碟快照
一般來說,這種快照的儲存費用較低,GCP 還可以使用標準(standard
)、即時(instant
)和封存(archive
)快照來備份 Persistent Disk。封存檔和標準快照是遠端磁碟備份,即時快照則是本機磁碟備份。
而像是標準快照只會按照快照總大小產生費用。舉例來說,假設在 5 個 TiB 永久磁碟上只使用 2 TiB 的磁碟空間,系統會針對已使用的 2 TiB 壓縮儲存空間(而非已佈建的 5 TiB)產生的完整磁碟空間收取快照大小。
3️⃣ 遷移到更經濟實惠的儲存類別
當您在 Google Cloud Storage(GCS)中儲存大量的物件(例如文件、圖像、影片等),這些物件的存儲成本可能會成為一個考慮因素。Google Cloud 提供了一項功能,稱為「儲存物件生命週期規則」,這讓您可以自動管理這些物件的存儲位置,以最大程度地節省成本。
這些生命週期規則允許您根據一組條件(例如物件的建立日期或即時狀態)將物件自動移動到不同的儲存類別中。舉例來說,您可以設置規則,讓 GCS 自動將一段時間未被存取的物件從標準存儲類別(例如 Regional Storage)移動到較低成本的存儲類別(例如 Nearline Storage 或 Coldline Storage),以節省成本。
然而,這些生命週期規則僅根據物件的屬性來進行操作,這些規則無法確定相關物件是否已被存取過。因此,有時您可能會希望手動處理某些物件,即使它們仍符合生命週期規則的條件。例如,即使某些較新的物件已有一段時間未被存取,但基於特定需求,您仍希望將它們移至 Nearline 儲存空間以節省成本。很多情況,就需要手動操作或使用其他自動化方案來處理這些物件的移動。
先前也有使用過類似的技術,進行 Cloud SQL 的節費處理
📙【How-to Guides】GCP FinOps — 善用 Scheduler 有效降低 CloudSQL 高昂費用
1️⃣ Delete unused reserved external IP addresses 實作
前置作業:建立 Compute Engine 虛擬機器並掛載靜態外部 IP ,並設定一個單獨的「未使用」的靜態外部 IP,作為模擬殘留的靜態外部 IP
- 制作 Cloud Functions 函數,以識別「未使用」的 IP
- 建立一個 Cloud Scheduler 作業,並設計 HTTP trigger,驅動 Cloud Function 定期移除未使用的 IP 或將其資料拋出的的 FinOps 計畫
以下是將提供的程式碼範例轉換為 Python 的版本,並添加了兩個功能:列印未使用的靜態 IP 地址並將其刪除。
❶ 單一專案(自行管理目的)
➋ 多專案且未引入組織層定義(常見的沙盒環境)
➌ 多專案且為組織層定義(公司環境或引入組織作為資安管理用途)
❶ 單一專案(自行管理目的)
(1) Web UI
最簡單就是到 Web UI > VPC 查看全部 IP 狀態,會看到 External IP 且使用者若有「⚠️無」的註記,表示未使用或清除掉的 IP 閒置資源
(2) gcloud 指令
使用 gcloud compute
這個也很方便,但要自動化還是稍嫌不夠
實驗關係,我們只留下 35.224.233.244
與 34.127.107.40
作為閒置資源
# 簡易輸出
$ gcloud compute addresses list
NAME: ooo
ADDRESS/RANGE: 35.224.233.244
TYPE: EXTERNAL
PURPOSE:
NETWORK:
REGION: us-central1
SUBNET:
STATUS: RESERVED
NAME: xxx
ADDRESS/RANGE: 34.127.107.40
TYPE: EXTERNAL
PURPOSE:
NETWORK:
REGION: us-west1
SUBNET:
STATUS: RESERVED
# 只取必要資訊出來
$ gcloud compute addresses list --filter="status=RESERVED" --format="table(name, address, region)"
# 格式如下
NAME: xxx
ADDRESS: 34.127.107.40
REGION: us-west1
# 再次整理成可以輸出至 CSV 上使用的格式
gcloud compute addresses list --filter="status=RESERVED" \
--format="csv(NAME, ADDRESS, REGION)" \
| awk 'NR==1 {print "NAME, ADDRESS, REGION"} NR>1 {print $0}'
NAME, ADDRESS, REGION, TYPE
ooo,35.224.233.244,us-central1, EXTERNAL
xxx,34.34.127.107.40,us-west1, EXTERNAL
使用 Google Cloud 的 gcloud
命令列工具列出所有的 Compute Engine 未使用的 IP:
--filter="status=RESERVED"
:篩選出顯示狀態為 "RESERVED" 的 IP 出來--format="csv(NAME, ADDRESS, REGION, TYPE)"
:指定輸出格式為 CSV,並僅包含名稱、地址和地區與類別欄位|
:管道符號,將第一個指令的輸出導向到下一個指令的輸入awk
:文本處理工具,用於對輸入進行處理NR==1 {print "NAME, ADDRESS, REGION"}
:當第一行時輸出 "NAME, ADDRESS, REGION, TYPE" 欄位名稱NR>1 {print $0}
:當二行及之後的行時,輸出整行內容
(3) Cloud Function — Python🐍
基本款式的自動化,搭建一個 Cloud Function 後,可以在使用 Cloud Scheduler 來排程輸出相關資訊至指定 channel,作為定期排查閒置資源的資訊
project
將專案名稱置入至 Cloud Function 執行階段環境變數中- 處理 Cloud Logging 中只顯示了 DEBUG 級別的記錄,但不顯示 INFO 級別的記錄,因此加上
logging.getLogger().setLevel(logging.INFO)
compute_client.list
中的list
是一個方法,它是AddressesClient
類別的一部分,並使用至google.cloud.compute_v1
模組- 這個
list
方法用於檢索指定區域內包含的地址列表。具體功能是根據提供的ListAddressesRequest
對象來發送請求並返回地址的分頁結果
程式範例參考
使用 Google Cloud 的官方 Python 客戶端庫(google-cloud-compute
)
- e.g.,
from google.cloud import compute_v1
- 用途:這個客戶端庫專門針對 GCP 上的 Compute Engine 服務進行了高層次的封裝,提供更簡化的操作界面
- 功能:提供了對 Compute Engine 相關資源(例如實例、磁盤、網路、地址等)的高層次抽象,開發者可以通過直觀的方法來執行各種操作
說明
list()
方法可以接受ListAddressesRequest
物件與關鍵字參數形式- 可以建立一個名為
ListAddressesRequest
的物件並包含了您要執行操作所需的所有參數,例如專案名稱、區域等 - 關鍵字參數也可以將專案名稱和區域作為關鍵字參數傳遞給
list()
方法 addresses
是 GCP Client Package 用來處理清單分頁的類<class ‘google.cloud.compute_v1.services.addresses.pagers.ListPager’>
,需要遍歷它並從中提取每個 IP 位址的詳細資訊- 遍歷的每個
address
的型態為<class ‘Address’>
,表示address
是一個Address
物件,可使用屬性來存取Address
物件中的各個欄位。例如,要取得位址的類型(address_type
)或位址值(address
)
# 印出 address 裡面的內容
id: 6074783325493135069
kind: "compute#address"
name: "ooo"
creation_timestamp: "2024-02-17T23:56:34.318-08:00"
region: "https://www.googleapis.com/compute/v1/projects/esun-cncf/regions/us-central1"
label_fingerprint: "42WmSpB8rSM="
status: "RESERVED"
address_type: "EXTERNAL"
description: ""
self_link: "https://www.googleapis.com/compute/v1/projects/esun-cncf/regions/us-central1/addresses/ooo"
address: "34.173.122.84"
network_tier: "PREMIUM"
並記得將 requirement.txt 加入套件依賴項
# Function dependencies, for example:
# package>=version
google-cloud-compute==1.16.1
執行結果如下,並照我們的 logging.info 印出每一個 IP 資訊
進階選項
⚠️ 這部份也看公司或個人使用的需求,如果發現有未使用的 IP 地址(狀態為 RESERVED
),除將其資訊添加到列表外,可以再調用 delete_address
函數來刪除未使用的 IP 地址。
自訂義 delete_address
function 係使用 compute_client
的 delete
method
def delete_address(compute_client, project_id, region, address_name):
# 刪除指定地區的 IP 地址
operation = compute_client.delete(project=project_id, region=region, address=address_name)
# 等待操作完成
operation.result()
➋ 多專案且未引入組織層定義(常見的沙盒環境)
一個專案還好,如果有數十個或上百個專案呢?另外,因為這個情境是沒有組織與 Folder 層級,就要思考擁有一組服務帳戶來存取多個專案層,作法如下:
- 在 Project A 選單中
IAM & Admin
選擇Service Accounts
- 因為它將在跨專案中使用,請明確定義它,這邊我們提供該服務帳號
Viewer
權限,您也可以向權限添加任何條件 - 切換到 Project B
IAM & Admin
選擇 ADD 👨 即 Add Principle to Project B,將先前Service account ID
引入並建立帳戶,一樣給予Viewer
權限
程式範例說明
註:初版雛型,驗證可行性使用,還有滿多如 print
及異常處理要調整
list_unused_static_ips
與get_all_regions
function 和 ❶ 單一專案用法一致list_projects
:作為主程式處理,紅框包括使用 resource manager 這個模組及藍框是在處理時有遇到不少專案未開啟 Compute Engine API,不加入此異常處理會直接報錯
is_compute_engine_api_enabled
function:功用如 doc string 所示
執行結果畫面(1/3 Pages)
第一次在 Lab 執行上面的健檢 script 時,就掃出有高達 20 多個的 External IP 閒置在雲端燒錢!Σ(;゚д゚) 約莫每月燒個 20 ✖ $10 USD
➌ 多專案且為組織層定義(公司環境或引入組織作為資安管理用途)
實作細節參照上面資訊,需要留意的是要在組織層級設定權限,GCP 預定義角色roles/browser
可以滿足相關需求,若是要自訂角色應該會有以下的權限要考量
- resourcemanager.projects.get
- resourcemanager.project.list
- resourcemanager.folders.get
- resourcemanager.folders.list
總結
糟糕,過程滿多細節不少,造成篇幅過長,2️⃣ & 3️⃣ 有空再放入 Part2 中。
2️⃣ Clean up unattached and orphaned persistent disks
3️⃣ 遷移到更經濟實惠的儲存類別
重點就是建立一個自動化的系統,用於識別和減少雲端支出的浪費或作一些資訊上的揭露。