Skip to main content

· 2 min read

GCS 本身對於存放的資料有不同分類,包含

  1. STANDARD
  2. NEARLINE
  3. COLDLINE
  4. ARCHIVE

分類的設定可以從

  1. 預設值 Storage class
  2. 設定 Lifecycle Rule,針對超過一定天數的檔案自動調整不同的分類

這幾個分類對消費者來說最大的影響可能就是存取與維護成本 以Cloud Storage pricing來說

存放本身的價格就是 STANDARD > NEARLINE > COLDLINE > ARCHIVE

但是如果今天想要存取資料(Retrieval fees)來說則要特別注意 STANDARD 本身免費,後面三者價格依序提高,其中以 COLDLINE 來說是 $0.02 GB

因此若需要存取 GCS 的話,則特別要注意目前檔案的屬性以及存取量,然後評估一下可能的花費 若有需要大量長期存取的,記得要切換成 STANDARD 模式,若幾乎不存取的就直接往後搬移減少儲存花費。

· 2 min read

預設的 istio-proxy 都會吃掉一些 CPU/Memory,當叢集內的 Pod 數量過多時,這些 sidecar 吃掉的數量非常可觀 如果是採用 istiooperator 的方式安裝,可以採用下列方式修改

...
spec:
values:
global:
proxy:
privileged: false
readinessFailureThreshold: 30
readinessInitialDelaySeconds: 1
readinessPeriodSeconds: 2
resources:
limits:
cpu: 2000m
memory: 1024Mi
requests:
cpu: 100m
memory: 128Mi

這個設定是 global 的設定,如果是單一的 Pod 要自行調整,可以於 Pod annotations 中加入列下資訊調整

annotations:
sidecar.istio.io/proxyCPU: 50m
sidecar.istio.io/proxyMemory: 128Mi

如果要更新 istio,建議參考官方 Canary Approach 的步驟,使用金絲雀部署的方式逐步調整 其原理很簡單

  1. 同時部署兩個版本的 istiod
  2. 逐步重啟 Pod 來套用新版本的 istio,直到所有 pod 都轉移到新版本的 istiod
  3. 移除舊的

基本上安裝過程要透過 "--revision=1-14-2" 的方式去打版本,安裝完畢後就是單純只有 control plane

接下來就取決當初如何設定 sidecare 的,如果是 namespace 的話,就可以直接改 namespace 裡面的

istio.io/rev=1-14-2

接下來就逐步重啟 Pod 就可以切換到新的 istio 版本。

另外可以透過 istioctl proxy-status 觀察每個 Pod 目前搭配的版本,透過此指令觀察升級進度

一旦全部升級完畢可以用 istioctl uninstall --revision 1-13-1 -y 來移除舊版本

· 3 min read

-- title: terraform 小筆記 authors: hwchiu tags:

當使用支援 Lock 的遠端 Backend 時,每次執行 Terraform 操作都會嘗試去 Lock,並且指令結束後去釋放 Lock 若執行到一半就透過 CTRL+C 強制離開可能會導致 Lock 沒有辦法順利結束,這時候下次執行就會遇到下列的問題

$ terraform apply
Acquiring state lock. This may take a few moments...

│ Error: Error acquiring the state lock

│ Error message: writing "gs://xxxxx/xxxxxxx/default.tflock" failed: googleapi: Error 412: At least one of the pre-conditions you specified did not hold., conditionNotMet
│ Lock Info:
│ ID: 1696991555387294
│ Path: gs://xxxxx/xxxxxxx/default.tflock
│ Operation: OperationTypeApply
│ Who: [email protected]
│ Version: 1.5.6
│ Created: 2022-10-11 02:32:35.12734 +0000 UTC
│ Info:

│ Terraform acquires a state lock to protect the state from being written
│ by multiple users at the same time. Please resolve the issue above and try
│ again. For most commands, you can disable locking with the "-lock=false"
│ flag, but this is not recommended.

當然上述原因也有可能是同時間真的有人其他人正在運行指令,把 lock 搶走,所以要先釐清 lock 卡住的情況是否如預期 如果是不預期的,就需要執行下列指令手動移除 lock

以上面輸出的 ID 當作內容,透過 terraform force-unlock 來解除

$ terraform force-unlock 1696991555387294
Do you really want to force-unlock?
Terraform will remove the lock on the remote state.
This will allow local Terraform commands to modify this state, even though it
may still be in use. Only 'yes' will be accepted to confirm.

Enter a value: yes

如果需要調整 Terraform State 的內容的話,通常可以使用

  1. terraform state list
  2. terraform state rm xxxx

手動將不需要的內容從 state 中移除

但是如果今天有更強硬的要求需要手動去修改內容的話,則需要

  1. terraform state pull > old_state
  2. vim a
  3. terraform state push old_state

這招很危險,要 100% 清楚自己做什麼同時也要有備份的 state 檔案,大意就是把 state 檔案抓下來並且直接修改,然後強行寫入回去,完全不需要額外 terraform plan/apply 的介入。 通常是 migration 過程希望可以順利轉移,同時又不希望遠方資源被影響,就可能會採用這種機制來直接修改 state.

此外轉移過程中如果有 provider 要處理,也可以透過使用 terraform state replace-provider 的方式來轉移,如下範例

terraform state replace-provider "registry.terraform.io/-/aws" "hashicorp/aws"

· 3 min read

GKE 環境上可以啟動 CA(Cluster-Autoscaling) 來根據資源使用量調整節點的數量,可以視為節點層級的 HPA

基本上只要節點的資源使用率過低,該節點就會被嘗試回收並且將所有的 Workload 都轉移到其他的節點

如果有特別特別重要的 Pod 希望該 Pod 能夠抑制 CA 的行為,有該 Pod 運行的節點都不能被踢除回收的話,可以於 annotations 中加入下列設定

    cluster-autoscaler.kubernetes.io/safe-to-evict: 'false'

該節點就會讓節點沒有辦法順利踢除因此最後不會回收該節點,該指令也要小心使用,若用不好可能會導致節點資源使用率過低最後產生額外的花費。

應用程式本身需要更長時間去調整 GracePeriod (預設 30 秒),可以直接修改 pod.spec.terminationGracePeriodSeconds 此欄位即可

$ kc explain pod.spec.terminationGracePeriodSeconds
KIND: Pod
VERSION: v1

FIELD: terminationGracePeriodSeconds <integer>

DESCRIPTION:
Optional duration in seconds the pod needs to terminate gracefully. May be
decreased in delete request. Value must be non-negative integer. The value
zero indicates stop immediately via the kill signal (no opportunity to shut
down). If this value is nil, the default grace period will be used instead.
The grace period is the duration in seconds after the processes running in
the pod are sent a termination signal and the time when the processes are
forcibly halted with a kill signal. Set this value longer than the expected
cleanup time for your process. Defaults to 30 seconds.

簡易 bash 腳本可以備份目前環境中的所有 secret 物件

function dump_secret {
for i in $(kubectl -n $1 get --no-headers secret | awk '{print $1}'); do
kubectl -n $1 get secret -o yaml $i > $i.yaml;
done
}

function dump_secrets {
for i in $(kubectl get ns --no-headers | awk '{print $1}'); do
if [ ! -d "./$i" ]; then
mkdir $i
fi
echo "Dump $i"
cd $i
dump_secret $i
cd ..
done
}

· One min read

修改 Author,可以 commit 時修改也可以事後修改

$ git commit -m "Test" --author "HungWei Chiu<[email protected]>"
$ git commit --amend --author "HungWei Chiu<[email protected]>" --no-edit

如果想要連 commit 一起修改且長期使用,比較簡單的方式就是直接設定 local user/email

$ git config --local user.email "[email protected]"
$ git config --local user.name "HungWei Chiu"

針對當前 commit 可以採用 --reset-author 的方式來修正

git commit  --amend --no-edit --reset-author

· 2 min read

GCP 的世界中透過 Cloud NAT 來處理對外流量,由該 NAT GW 進行 SNAT 的轉換。 之前遇到一個問題是某對外服務的連線會不定時 timeout 無法連線,輾轉各種測試最後終於發現問題出在 Cloud NAT 上

Cloud NAT 上有一個設定稱為 Port Reservation 該設定會影響 Cloud NAT 要如何幫後方所有流量進行 SNAT,要用哪個 Source IP 以及哪個 Source Port 去處理。

其中有一個設定是 "Minimum Ports per VM",這個欄位的意思是每個 VM 上可以對相同目標 (IP + Port) 同時發起多少條連線 舉例來說,假設今天想要連接 1.2.3.4:2345 這個網站,且設定為 32,那就代表這個 VM 上最多只能有 32 條連線,超過的就會被 Cloud NAT 丟掉而無法處理,最後產生 timeout

如果今天 VM 規格夠大,上面部署 GKE 同時有多個相同副本的 Pod 同時運行,那就有可能會踩到這個數字導致連線 timeout,可以到 Cloud NAT 的設定將其調整,預設應該是 64。

另外 Cloud NAT 本身對外流量都會收費,要計算流量資訊需要到 VPC 去打開 Logging 紀錄,這個 Logging 也需要特別設定取樣頻率,因為會收費 所以設定完成後,就可以於 Cloud Logging 收到相關資訊,可以把 Logging 轉換為 Metrics 去計算流量的走向,譬如以 IP/hostname 為基準去分析到底流量都跑去那,再透過這個資訊來除錯省錢

· One min read

GCP 提供 OS login 等方式可以讓使用者透過 gcloud compute ssh 等方式登入到沒有 public IP 的機器上,但是每次設定上總是卡各種權限 而預設的 IAM Roles 裡面又沒有相關的身份可以一次搞定,常常要到處找到底缺哪個角色 經過一番努力跟嘗試後,確認只要給予下列權限就可以執行 gcloud compute ssh

compute.instances.osLogin
compute.instances.setMetadata
compute.instances.use
iam.serviceAccounts.actAs
iap.tunnelInstances.accessViaIAP
networkmanagement.connectivitytests.create
serviceusage.services.enable

因此創立一個新角色給予上面的權限,然後再把該角色綁定到目標使用者或群組,應該就可以透過 gcloud compute ssh 到遠方機器了。

· 2 min read

GCP CloudSQL 本身的收費機制常見取決於

  1. 機器等級強度,若有開 HA 模式則價格兩倍
  2. 硬碟使用量

其中 (1) 的主要是由 vCPU 與 Memory 的用量來決定價格,詳細資訊可以參閱網頁介紹

另外 CloudSQL 本身是可以直接升級機器強度的,可以手動也可以透過 Terraform 來管理,不過升級過程中 副會處於 downtime 不能存取階段,升級時間處決於當前機器的強度與資料量,短則一分鐘,長20分鐘都有可能。

另外硬碟使用量的部分有兩種設定機制

  1. 固定硬碟用量
  2. 動態調整用量,當硬碟用量超過 90% 以上後就會自動調整用量

另外硬碟用量也會有收費的問題,假如當硬碟用量清空想要縮小硬碟用量,這部分目前還沒有辦法操作,需要開 Support ticket 請 GCP 幫忙縮小硬碟空間。

· 2 min read

因為 HPA 或是 CA 等調度使得 Ingester 等 Pod 重啟後,有機會踩到 Bug 使得系統中存在 unhealthy instance. 常見的錯誤訊息為 too many unhealthy instances in the ring

這種情況的解法有兩個

  1. 手動移除
  2. 設定環境讓其自動移除

手動移除的部分需要存取 loki-distributor 的 UI,譬如

$ kubectl port-forward svc/loki-distributor 3100:3100

接者存取 localhost:3100/ring 的網頁,就可以看到所有 instance 的資訊,針對不健康的 instance 從網頁中將其遺忘即可。

另外也可以部署安裝 Loki(Helm) 的過程中設定 ingester 的參數讓其自動忘記,未來就不需要手動設定

ingester:
autoforget_unhealthy: true

另外部署效能上有不少參數需要調整,通常都是 limits_config,新舊版本有些設定有差 然後 querier 以及 ingester 需要額外調整自己的 resource 與 HPA 的數量,根據使用者習慣以及用量來調整已提升整體吞吐量

loki:
config: |
server:
grpc_server_max_recv_msg_size: 104857600
grpc_server_max_send_msg_size: 104857600
http_server_read_timeout: 10m
http_server_write_timeout: 10m
ingester:
chunk_idle_period: 10m
chunk_block_size: 262144
chunk_encoding: snappy
chunk_retain_period: 1m
max_transfer_retries: 0
wal:
dir: /var/loki/wal
limits_config:
max_global_streams_per_user: 15000
enforce_metric_name: false
reject_old_samples: true
reject_old_samples_max_age: 168h
max_cache_freshness_per_query: 10m
retention_period: 2160h
split_queries_by_interval: 30m
ingestion_rate_mb: 32
ingestion_burst_size_mb: 64
max_query_parallelism: 256
max_cache_freshness_per_query: 10m
per_stream_rate_limit_burst: 15MB
gateway:
nginxConfig:
httpSnippet: client_max_body_size 50M;
serverSnippet: |-
client_max_body_size 50M;
proxy_read_timeout 600s;
proxy_send_timeout 600s;

· 2 min read

Kustomize 可以支援使用 Helm 來強化整個靈活性 以下是一個使用 Helm Chart 的範例

$ cat kustomization.yaml
helmCharts:
- name: redis-cluster
includeCRDs: false
valuesFile: redis.yaml
releaseName: redis-cluster
namespace: dev
version: 9.0.5
repo: https://charts.bitnami.com/bitnami

準備一個名為 redis.yaml 的檔案,就如同平常使用 helm values 一樣

接下來可以使用 kustomize 來嘗試產生最後部署的 YAML

$ kustomize build --enable-helm  > temp
$ ls -l w
-rw-r--r-- 1 hwchiu momo 123257 Oct 11 11:18 temp

想嘗試使用 kubectl 但是目前都會失敗

$ kubectl apply --dry-run=client -o yaml -k .
error: trouble configuring builtin HelmChartInflationGenerator with config: `
name: redis-cluster
namespace: dev
releaseName: redis-cluster
repo: https://charts.bitnami.com/bitnami
valuesFile: redis.yaml
version: 9.0.5
`: must specify --enable-helm
$ kubectl apply --dry-run=client -o yaml -k . --enable-helm
error: unknown flag: --enable-helm
See 'kubectl apply --help' for usage.

另外如果要於 ArgoCD 中使用,需要修改 argocd-cm 加入下列參數


apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
data:
kustomize.buildOptions: --enable-helm