星期六, 3月 28, 2026

Bigquery with Grafana 規劃小記

20260328


Bigquery with Grafana 規劃小記



今天來寫 Bigquery with Grafana 規劃

目的: 使用 Grafana 呈現 Bigquery 查詢的結果


目前規劃想法

  • 使用 Cloud Armor 搭配 Load Balancer 達成加密連線與白名單過濾

  • Grafana 目前使用 GCE 方式運作, 使用獨立 Service Account 來作為此 GCE default account , 只給予 BigQuery Job User 與要請求單位的 BigQuery Viewer 權限, 使用這樣的方式達成無金鑰驗證方式

  • Grafana GCE 沒有配置外部 IP, 透過 Cloud NAT 方式來進行套件更新, 管理員則透過 IAP 方式進行存取

  • 刪除預設網段, 建立自訂網段與Subnet



與 Gemini CLI 合作建立部署的 script

以下提供參考 deploy_grafana_alb.sh



#!/bin/bash


# 終止執行,如果發生任何錯誤

set -e


# ==========================================

# 參數設定區 (請依照您的實際環境修改)

# ==========================================

# 您的 Grafana 專案 ID

PROJECT_GRAFANA="your-grafana-project-id"


# 目標 BigQuery 帳單專案 (可以設定多個,請以空白分隔或換行)

TARGET_BILLING_PROJECTS=(

    "your-billing-project-a"

    "your-billing-project-b"

    # "your-billing-project-c"

)


# 資源名稱與設定

SA_NAME="grafana-bq-reader"

SA_EMAIL="${SA_NAME}@${PROJECT_GRAFANA}.iam.gserviceaccount.com"

ZONE="asia-east1-b" # 請選擇適合您的可用區

REGION="asia-east1"

VM_NAME="grafana-server"

IG_NAME="grafana-ig"

NETWORK_TAG="grafana-tag"

STATIC_IP_NAME="grafana-lb-ip"

ARMOR_POLICY_NAME="grafana-whitelist"


# 網路與基礎設施設定

VPC_NAME="grafana-vpc"

SUBNET_NAME="grafana-subnet"

SUBNET_RANGE="10.10.0.0/24"

ROUTER_NAME="grafana-router"

NAT_NAME="grafana-nat"


# 您的網域名稱,請替換成實際使用的網域 (例如: grafana.yourdomain.com)

DOMAIN_NAME="grafana.yourdomain.com"


# 您的白名單 IP,請替換成實際 IP (例如: 203.0.113.50/32)

# 支援多個 IP請以逗號分隔 (例如: "IP1/32,IP2/24")

WHITELIST_IPS="YOUR_IP_ADDRESS/32"


# ==========================================

# 防呆檢查

# ==========================================

if [ "$PROJECT_GRAFANA" = "your-grafana-project-id" ] || \

   [ "$WHITELIST_IPS" = "YOUR_IP_ADDRESS/32" ] || \

   [ "${TARGET_BILLING_PROJECTS[0]}" = "your-billing-project-a" ]; then

    echo "❌ 錯誤:請先使用文字編輯器開啟此腳本,修改「參數設定區」的預設變數!"

    echo "請特別注意填寫正確的 PROJECT_GRAFANA、TARGET_BILLING_PROJECTS 與 WHITELIST_IPS。"

    exit 1

fi


echo "=========================================="

echo "🚀 開始執行 Grafana + ALB + Cloud Armor 自動化部署"

echo "專案 ID: $PROJECT_GRAFANA"

echo "=========================================="


# 設定 gcloud 預設專案

gcloud config set project $PROJECT_GRAFANA


echo -e "\n[階段零] 檢查並啟用必要的 GCP API..."

echo "👉 啟用 Compute Engine API 與 Certificate Manager API (可能需要幾分鐘)..."

gcloud services enable compute.googleapis.com

gcloud services enable certificatemanager.googleapis.com


echo -e "\n[階段零點五] 清理預設 VPC (Default VPC)..."

echo "👉 嘗試刪除預設 VPC 相關之防火牆規則 (若存在)..."

gcloud compute firewall-rules list --filter="network:default" --format="value(name)" > /tmp/default_fw_rules.txt || true

if [ -s /tmp/default_fw_rules.txt ]; then

    cat /tmp/default_fw_rules.txt | xargs -r gcloud compute firewall-rules delete --quiet || true

fi

rm -f /tmp/default_fw_rules.txt || true


echo "👉 嘗試刪除預設 VPC 網路 (包含預設子網路)..."

gcloud compute networks delete default --quiet || true


echo -e "\n[階段一] IAM 與服務帳戶 (Service Account) 設定"

echo "👉 1. 在 Grafana 專案建立專屬 SA..."

# 取得目前日期

CREATE_DATE=$(date +"%Y-%m-%d")

# 建立 SA (若已存在會報錯,可略過)

gcloud iam service-accounts create $SA_NAME \

    --description="Service Account for Grafana to read BigQuery (Created by Gemini on $CREATE_DATE)" \

    --display-name="Grafana BQ Reader" || true


echo "等待 10 秒讓 IAM 權限傳播..."

sleep 10


echo "👉 2. 授予 BigQuery Job User 角色..."

gcloud projects add-iam-policy-binding $PROJECT_GRAFANA \

    --member="serviceAccount:${SA_EMAIL}" \

    --role="roles/bigquery.jobUser"


echo "👉 3. 授予跨專案 BigQuery Data Viewer 角色..."

for project in "${TARGET_BILLING_PROJECTS[@]}"; do

    echo "  - 設定專案: $project"

    gcloud projects add-iam-policy-binding "$project" \

        --member="serviceAccount:${SA_EMAIL}" \

        --role="roles/bigquery.dataViewer"

done


echo -e "\n🔍 正在查詢 $ZONE 區域內可用的 E2 系列機器規格..."

gcloud compute machine-types list --zones=$ZONE --filter="name ~ '^e2-'" --format="table(name, vcpus, memoryMb)"


echo ""

echo "💡 常見規格價格參考 (依區域與折扣可能有所不同):"

echo "  - e2-micro (2 vCPU, 1GB RAM)    : 約 \$7 USD/月 (適用於極小流量)"

echo "  - e2-small (2 vCPU, 2GB RAM)    : 約 \$13 USD/月 (適合個人小專案)"

echo "  - e2-medium (2 vCPU, 4GB RAM)   : 約 \$25 USD/月 (建議的最小正式環境配置)"

echo "  - e2-standard-2 (2 vCPU, 8GB RAM): 約 \$49 USD/月 (適合企業級正式環境)"

echo ""

printf "請輸入您要使用的機器規格 [直接按 Enter 預設使用 e2-medium]: "

read VM_MACHINE_TYPE

VM_MACHINE_TYPE=${VM_MACHINE_TYPE:-e2-medium}

echo "✅ 已選擇機器規格: $VM_MACHINE_TYPE"


echo -e "\n🔍 正在設定硬碟 (Disk)..."

printf "請輸入開機磁碟大小 (GB) [直接按 Enter 預設使用 20]: "

read DISK_SIZE

DISK_SIZE=${DISK_SIZE:-20}


echo "💡 磁碟類型參考:"

echo "  - pd-standard : 標準永久磁碟 (最便宜)"

echo "  - pd-balanced : 平衡永久磁碟 (建議,效能與價格平衡)"

echo "  - pd-ssd      : SSD 永久磁碟 (效能最高)"

printf "請輸入磁碟類型 [直接按 Enter 預設使用 pd-balanced]: "

read DISK_TYPE

DISK_TYPE=${DISK_TYPE:-pd-balanced}

echo "✅ 已選擇磁碟: ${DISK_SIZE}GB, 類型: $DISK_TYPE"


echo -e "\n🔍 正在設定作業系統 (OS Image)..."

echo "請選擇您要使用的作業系統:"

echo "  1) Debian 12 (預設)"

echo "  2) Ubuntu 22.04 LTS"

echo "  3) Ubuntu 24.04 LTS"

echo "  4) Oracle Linux 9"

printf "請輸入選項 [1-4, 直接按 Enter 預設使用 1]: "

read OS_CHOICE


case $OS_CHOICE in

    2)

        IMAGE_PROJECT="ubuntu-os-cloud"

        IMAGE_FAMILY="ubuntu-2204-lts"

        echo "✅ 已選擇 OS: Ubuntu 22.04 LTS"

        STARTUP_SCRIPT="#!/bin/bash

exec > /var/log/grafana_install.log 2>&1

echo \"開始安裝 Grafana (Ubuntu 22.04)...\"

export DEBIAN_FRONTEND=noninteractive

apt-get update

apt-get install -y apt-transport-https software-properties-common wget

echo \"正在安裝 Google Cloud Ops Agent...\"

curl -sSO https://dl.google.com/cloudagents/add-google-cloud-ops-agent-repo.sh

bash add-google-cloud-ops-agent-repo.sh --also-install

mkdir -p /etc/apt/keyrings/

wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | tee /etc/apt/keyrings/grafana.gpg > /dev/null

echo \"deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main\" | tee /etc/apt/sources.list.d/grafana.list

apt-get update

apt-get install -y grafana

echo \"設定 Grafana...\"

sed -i \"s/;domain = localhost/domain = ${DOMAIN_NAME}/\" /etc/grafana/grafana.ini

sed -i \"s|;root_url = %(protocol)s://%(domain)s:%(http_port)s/|root_url = https://${DOMAIN_NAME}/|\" /etc/grafana/grafana.ini

sed -i \"s/;cookie_secure = false/cookie_secure = true/\" /etc/grafana/grafana.ini

systemctl daemon-reload

systemctl enable grafana-server

systemctl start grafana-server

echo \"Grafana 安裝與設定完成!\"

"

        ;;

    3)

        IMAGE_PROJECT="ubuntu-os-cloud"

        IMAGE_FAMILY="ubuntu-2404-lts-amd64"

        echo "✅ 已選擇 OS: Ubuntu 24.04 LTS"

        STARTUP_SCRIPT="#!/bin/bash

exec > /var/log/grafana_install.log 2>&1

echo \"開始安裝 Grafana (Ubuntu 24.04)...\"

export DEBIAN_FRONTEND=noninteractive

apt-get update

apt-get install -y apt-transport-https software-properties-common wget

echo \"正在安裝 Google Cloud Ops Agent...\"

curl -sSO https://dl.google.com/cloudagents/add-google-cloud-ops-agent-repo.sh

bash add-google-cloud-ops-agent-repo.sh --also-install

mkdir -p /etc/apt/keyrings/

wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | tee /etc/apt/keyrings/grafana.gpg > /dev/null

echo \"deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main\" | tee /etc/apt/sources.list.d/grafana.list

apt-get update

apt-get install -y grafana

echo \"設定 Grafana...\"

sed -i \"s/;domain = localhost/domain = ${DOMAIN_NAME}/\" /etc/grafana/grafana.ini

sed -i \"s|;root_url = %(protocol)s://%(domain)s:%(http_port)s/|root_url = https://${DOMAIN_NAME}/|\" /etc/grafana/grafana.ini

sed -i \"s/;cookie_secure = false/cookie_secure = true/\" /etc/grafana/grafana.ini

systemctl daemon-reload

systemctl enable grafana-server

systemctl start grafana-server

echo \"Grafana 安裝與設定完成!\"

"

        ;;

    4)

        IMAGE_PROJECT="oracle-os-cloud"

        IMAGE_FAMILY="oracle-linux-9"

        echo "✅ 已選擇 OS: Oracle Linux 9"

        STARTUP_SCRIPT="#!/bin/bash

exec > /var/log/grafana_install.log 2>&1

echo \"開始安裝 Grafana (Oracle Linux 9)...\"

echo \"正在安裝 Google Cloud Ops Agent...\"

curl -sSO https://dl.google.com/cloudagents/add-google-cloud-ops-agent-repo.sh

bash add-google-cloud-ops-agent-repo.sh --also-install

yum install -y https://dl.grafana.com/enterprise/release/grafana-enterprise-10.4.1-1.x86_64.rpm

echo \"設定 Grafana...\"

sed -i \"s/;domain = localhost/domain = ${DOMAIN_NAME}/\" /etc/grafana/grafana.ini

sed -i \"s|;root_url = %(protocol)s://%(domain)s:%(http_port)s/|root_url = https://${DOMAIN_NAME}/|\" /etc/grafana/grafana.ini

sed -i \"s/;cookie_secure = false/cookie_secure = true/\" /etc/grafana/grafana.ini

systemctl daemon-reload

systemctl enable grafana-server

systemctl start grafana-server

echo \"Grafana 安裝與設定完成!\"

"

        ;;

    *)

        IMAGE_PROJECT="debian-cloud"

        IMAGE_FAMILY="debian-12"

        echo "✅ 已選擇 OS: Debian 12 (預設)"

        STARTUP_SCRIPT="#!/bin/bash

exec > /var/log/grafana_install.log 2>&1

echo \"開始安裝 Grafana (Debian 12)...\"

export DEBIAN_FRONTEND=noninteractive

apt-get update

apt-get install -y apt-transport-https software-properties-common wget

echo \"正在安裝 Google Cloud Ops Agent...\"

curl -sSO https://dl.google.com/cloudagents/add-google-cloud-ops-agent-repo.sh

bash add-google-cloud-ops-agent-repo.sh --also-install

mkdir -p /etc/apt/keyrings/

wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | tee /etc/apt/keyrings/grafana.gpg > /dev/null

echo \"deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main\" | tee /etc/apt/sources.list.d/grafana.list

apt-get update

apt-get install -y grafana

echo \"設定 Grafana...\"

sed -i \"s/;domain = localhost/domain = ${DOMAIN_NAME}/\" /etc/grafana/grafana.ini

sed -i \"s|;root_url = %(protocol)s://%(domain)s:%(http_port)s/|root_url = https://${DOMAIN_NAME}/|\" /etc/grafana/grafana.ini

sed -i \"s/;cookie_secure = false/cookie_secure = true/\" /etc/grafana/grafana.ini

systemctl daemon-reload

systemctl enable grafana-server

systemctl start grafana-server

echo \"Grafana 安裝與設定完成!\"

"

        ;;

esac


echo -e "\n[階段二] 自訂 VPC 網路與 Cloud NAT 設定"

echo "👉 1. 建立自訂 VPC 網路 ($VPC_NAME)..."

gcloud compute networks create $VPC_NAME --subnet-mode=custom


echo "👉 2. 建立自訂子網路 ($SUBNET_NAME)..."

gcloud compute networks subnets create $SUBNET_NAME \

    --network=$VPC_NAME \

    --region=$REGION \

    --range=$SUBNET_RANGE


echo "👉 3. 建立 Cloud Router ($ROUTER_NAME)..."

gcloud compute routers create $ROUTER_NAME \

    --network=$VPC_NAME \

    --region=$REGION


echo "👉 4. 建立 Cloud NAT ($NAT_NAME)..."

gcloud compute routers nats create $NAT_NAME \

    --router=$ROUTER_NAME \

    --region=$REGION \

    --auto-allocate-nat-external-ips \

    --nat-all-subnet-ip-ranges


echo -e "\n[階段三] GCE 虛擬機器與執行個體群組"

echo "👉 1. 建立 GCE 執行個體 (無外部 IP,透過 startup-script 自動安裝 Grafana)..."

gcloud compute instances create $VM_NAME \

    --description="Grafana Server VM (Created by Gemini on $CREATE_DATE)" \

    --zone=$ZONE \

    --machine-type=$VM_MACHINE_TYPE \

    --image-project=$IMAGE_PROJECT \

    --image-family=$IMAGE_FAMILY \

    --boot-disk-size=$DISK_SIZE \

    --boot-disk-type=$DISK_TYPE \

    --network=$VPC_NAME \

    --subnet=$SUBNET_NAME \

    --no-address \

    --service-account=${SA_EMAIL} \

    --scopes=https://www.googleapis.com/auth/cloud-platform \

    --tags=$NETWORK_TAG \

    --metadata=startup-script="$STARTUP_SCRIPT"


echo "👉 2. 建立非代管執行個體群組並加入 VM..."

gcloud compute instance-groups unmanaged create $IG_NAME \

    --description="Grafana Instance Group (Created by Gemini on $CREATE_DATE)" \

    --zone=$ZONE


gcloud compute instance-groups unmanaged add-instances $IG_NAME \

    --zone=$ZONE \

    --instances=$VM_NAME


echo "👉 3. 設定執行個體群組 Named Port..."

gcloud compute instance-groups unmanaged set-named-ports $IG_NAME \

    --named-ports=http:3000 \

    --zone=$ZONE


echo -e "\n[階段四] VPC 防火牆設定"

echo "👉 1. 建立防火牆規則以允許 GCP LB 健康檢查連線..."

gcloud compute firewall-rules create allow-gcp-lb-to-grafana \

    --description="Allow GCP Load Balancer health checks to Grafana (Created by Gemini on $CREATE_DATE)" \

    --direction=INGRESS \

    --priority=1000 \

    --network=$VPC_NAME \

    --action=ALLOW \

    --rules=tcp:3000 \

    --source-ranges=130.211.0.0/22,35.191.0.0/16 \

    --target-tags=$NETWORK_TAG


echo "👉 2. 建立防火牆規則以允許透過 IAP 安全 SSH 連線..."

gcloud compute firewall-rules create allow-iap-ssh-to-grafana \

    --description="Allow IAP SSH access to internal Grafana VM (Created by Gemini on $CREATE_DATE)" \

    --direction=INGRESS \

    --priority=1000 \

    --network=$VPC_NAME \

    --action=ALLOW \

    --rules=tcp:22 \

    --source-ranges=35.235.240.0/20 \

    --target-tags=$NETWORK_TAG


echo -e "\n[階段五] 保留靜態 IP"

echo "👉 保留 GCP 全域靜態外部 IP..."

gcloud compute addresses create $STATIC_IP_NAME \

    --description="Static IP for Grafana ALB (Created by Gemini on $CREATE_DATE)" \

    --network-tier=PREMIUM \

    --global || true


LB_IP=$(gcloud compute addresses describe $STATIC_IP_NAME --global --format="value(address)")

echo "✅ 獲得靜態 IP: $LB_IP"

echo "⚠️ 請立即前往 Cloudflare (或其他 DNS 提供商),將 $DOMAIN_NAME 的 A 紀錄指向 $LB_IP (若使用 Cloudflare 請設為 DNS Only 灰色雲朵)"

printf "請在完成 DNS 設定後,按 Enter 鍵繼續..."

read


echo -e "\n[階段六] Cloud Armor 白名單設定"

echo "👉 1. 建立 Cloud Armor 政策 (預設拒絕)..."

gcloud compute security-policies create $ARMOR_POLICY_NAME \

    --description="Whitelist for Grafana (Created by Gemini on $CREATE_DATE)" || true


# 更改預設規則為 403 拒絕

gcloud compute security-policies rules update 2147483647 \

    --security-policy=$ARMOR_POLICY_NAME \

    --action="deny-403"


echo "👉 2. 新增白名單規則 (允許 $WHITELIST_IPS)..."

gcloud compute security-policies rules create 1000 \

    --description="Allow specific IPs to access Grafana (Created by Gemini on $CREATE_DATE)" \

    --security-policy=$ARMOR_POLICY_NAME \

    --src-ip-ranges="$WHITELIST_IPS" \

    --action="allow" || true


echo -e "\n[階段七] Application Load Balancer (ALB) 與 SSL 設定"

echo "👉 1. 建立健康檢查..."

gcloud compute health-checks create http grafana-hc \

    --description="Health check for Grafana backend (Created by Gemini on $CREATE_DATE)" \

    --port=3000 \

    --request-path="/api/health" || true


echo "👉 2. 建立後端服務並套用 Cloud Armor..."

gcloud compute backend-services create grafana-backend \

    --description="Backend service for Grafana ALB (Created by Gemini on $CREATE_DATE)" \

    --load-balancing-scheme=EXTERNAL \

    --protocol=HTTP \

    --port-name=http \

    --health-checks=grafana-hc \

    --global || true


gcloud compute backend-services update grafana-backend \

    --security-policy=$ARMOR_POLICY_NAME \

    --global


echo "👉 3. 將執行個體群組加入後端服務..."

gcloud compute backend-services add-backend grafana-backend \

    --instance-group=$IG_NAME \

    --instance-group-zone=$ZONE \

    --global || true


echo "👉 4. 建立 URL Map..."

gcloud compute url-maps create grafana-url-map \

    --description="URL Map for Grafana ALB (Created by Gemini on $CREATE_DATE)" \

    --default-service=grafana-backend || true


echo "👉 5. 建立 Google 代管 SSL 憑證..."

gcloud compute ssl-certificates create grafana-cert \

    --description="Managed SSL Certificate for Grafana (Created by Gemini on $CREATE_DATE)" \

    --domains=$DOMAIN_NAME || true


echo "👉 6. 建立 Target HTTPS Proxy..."

gcloud compute target-https-proxies create grafana-https-proxy \

    --description="Target HTTPS Proxy for Grafana (Created by Gemini on $CREATE_DATE)" \

    --url-map=grafana-url-map \

    --ssl-certificates=grafana-cert || true


echo "👉 7. 建立全域轉送規則 (Forwarding Rule)..."

gcloud compute forwarding-rules create grafana-https-rule \

    --description="Global forwarding rule for Grafana ALB (Created by Gemini on $CREATE_DATE)" \

    --load-balancing-scheme=EXTERNAL \

    --network-tier=PREMIUM \

    --address=$STATIC_IP_NAME \

    --global \

    --target-https-proxy=grafana-https-proxy \

    --ports=443 || true


echo "=========================================="

echo "✅ 基礎設施部署腳本執行完畢!"

echo "Grafana 與 Ops Agent 正在背景自動安裝與設定 (約需 2-3 分鐘)。"

echo ""

echo "🔐 Grafana 登入資訊:"

echo "   - 預設帳號:admin"

echo "   - 預設密碼:admin"

echo "   ⚠️ 安全提醒:首次登入後,系統會要求您立即變更密碼,請務必設定強密碼。"

echo ""

echo "後續檢查步驟:"

echo "1. 若需確認安裝進度,可透過 IAP SSH 進入內部 VM ($VM_NAME) 執行:"

echo "   gcloud compute ssh $VM_NAME --zone=$ZONE --tunnel-through-iap --command=\"tail -f /var/log/grafana_install.log\""

echo "2. 憑證核發通常需要 15~30 分鐘,請耐心等待。"

echo "3. 等待完成後,即可開啟瀏覽器存取: https://$DOMAIN_NAME"

echo "=========================================="


現在真的是進入 人與 AI 合作時代


~ enjoy it


References

  • Gemini CLI

沒有留言: