Skip to main content

· 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

· 2 min read

Kubernetes 內的容器運行上可能會遇到 OOM (Out Of Memory),通長會有兩種情況

  1. 應用程式本身的 Memory Limit 沒有設定好,因此踩到上限被移除
  2. 眾多應用程式的 Memory Request 沒有設定好,導致系統資源被互搶直到系統沒有足夠記憶體,因此觸發 OOM 開始砍人

這類型的事件可以透過下列的方式去觀測

  1. 安裝 kube event exporter,該專案會將所有 event 以不同的方式輸出。簡易方式可以採用 stdout 的方式輸出
  2. 透過 Logging 系統收集 stdout 的 log,從中分析是否有 OOM 的事件發生,有的話可以發送 Alert

以 Loki 來說,可以採用下列語法去過ㄌㄩ

count_over_time({container="kube-event-exporter"}[1m] | json | __error__ != "JSONParserErr" | reason="OOMKilling")

· 2 min read

GCP 本身有自己的 IAM roles,可以讓所有 GCP 使用者有特定的權限去存取 GKE 叢集,譬如

  1. Kubernetes Engine Cluster Admin
  2. Kubernetes Engine Cluster Viewer
  3. Kubernetes Engine Developer

然而這類型的設定卻有一些限制

  1. 沒有辦法針對 namespace 內去詳細設定
  2. 不方便針對 cluster 層級設定,譬如一個專案內若是有多個 GKE cluster,則權限會全部套用

但是這類型的操作與 gcloud 的整合非常順,可以很輕鬆的就讓所有團得人員獲得 GKE 的存取權限,進而使用 kubectl 等指令

若今天想要修改權限改使用 Kubernetes RBAC 的方式,達到稍微細緻以 namespace 為基底的權限, 並且以群組信箱來當作 subjet 的話則需要一些額外步驟

  1. 將 Google Group 與 GKE 連動,可參考 GKE RBAC
  2. 於 Google Group 將使用者都加入到該群組中
  3. 於 GCP 給予該 Google Group ([email protected]) 一個 Kubernetes Engine Cluster Viewer 的權限,因為所有人都至少要能夠透過 gcloud 去認證獲得 KUBECONFIG 來存取,因此至少要可讀

另外群組的部分,可以採用 nested group,就是所有真正的 group 都加入到上述的 gke-security-groups 內,因此 RBAC 設定的部分就可以採用 [email protected], [email protected] 等方式來設定。

一切完畢後就依照 Kubernetes RBAC 的設定,準備 Role/RoleBinding,其中 RoleBinding 的 Subjects 改成

---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: xxxxxxxxxx
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: xxxxxxxxxxxx
roleRef:
kind: Role
name: xxxxxxxxxx
apiGroup: rbac.authorization.k8s.io

· One min read

練習可以使用各種網頁資源來產生 token,但是如果是內部服務則不要使用那類型的服務,以免有任何資訊被第三方掌握

快速產生的方式可以採用 nodejs 來搞定

先準備一個下列檔案

$ cat jwt.js
var jwt = require('jsonwebtoken');
var token = jwt.sign({
"data": "my value",
"permissions": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10
],
}, 'secret_file', {expiresIn: "365 days"});

console.log(token)

$ node jwt.js
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJnZyI6Im5vbm9ubyIsInBlcm1pc3Npb25zIjpbMSwyLDMsNCw1LDYsNyw4LDksMTBdLCJpYXQiOjE2OTY5OTM1NjksImV4cCI6MTcyODUyOTU2OX0.b-5UiuaNdFPuwgJMn8Ji3v803OA00qA8aSwetY7XDEY