顯示具有 aws 標籤的文章。 顯示所有文章
顯示具有 aws 標籤的文章。 顯示所有文章

2025年4月7日 星期一

Terraform - aws_eks_cluster 開始支援 auto mode 之後的雷

AWS EKS cluster 在 auto mode 出現之前, aws_eks_cluster 通常不會去設定這幾個選項, 預設如下:

  bootstrap_self_managed_addons = true

  access_config {
    authentication_mode                         = "CONFIG_MAP"
    bootstrap_cluster_creator_admin_permissions = false #1
  }

但是 auto mode 出現之後, 有用 auto mode 就需要這樣設定:

  bootstrap_self_managed_addons = false

  access_config {
    authentication_mode                         = "API_AND_CONFIG_MAP"
    bootstrap_cluster_creator_admin_permissions = false
  }

沒用 auto mode 就需要這樣設定:

  bootstrap_self_managed_addons = true

  access_config {
    authentication_mode                         = "CONFIG_MAP"
    bootstrap_cluster_creator_admin_permissions = true #2
  }

有發現 #1 跟 #2 設定值不同

在 auto mode 出現之前已經開起來的 EKS cluster 目前還沒出現明顯異常, 但是在 terraform 裡面還是會做成設定一致, 所以就來試著更動已存在的 EKS cluster 這個設定.

  # module.cellar.module.eks.module.cluster["foobar"].aws_eks_cluster.this must be replaced
  -/+ resource "aws_eks_cluster" "this" {
        ...

      ~ access_config {
          ~ bootstrap_cluster_creator_admin_permissions = false -> true # forces replacement
            # (1 unchanged attribute hidden)
        }

        ...
    }

乾~ 更動 bootstrap_cluster_creator_admin_permissions 的設定竟然要把 cluster 砍掉重練!

為了往後新的 EKS cluster 設定的正確性, 只好在 aws_eks_cluster 裡面放一段 lifecycle 讓已存在的 cluster 不受影響:

  lifecycle {
    ignore_changes = [
      access_config[0].bootstrap_cluster_creator_admin_permissions
    ]
  }

2025年3月10日 星期一

Kubernetes - tuning containers resources requests and limits

Target
- daemonsets
- deployment
- statefulsets


Policy
- request cpu 單位以十進位設定
  - 像是 50m 100m 200m 250m 500m 1000m(or 1)
- request memory 單位以二進位設定
  - 像是 16Mi 32Mi 64Mi 128Mi 256Mi 384Mi 512Mi 768Mi 1024Mi(or 1Gi)
- request memory 是 node 實際上能放進 pod 的基本量, pod 塞不進 pod 就得生出新的 node 來放.
- pod cpu 吃到超過 limit cpu, 會被卡住等下一輪資源繼續跑, 不會被砍掉.
- pod memory 吃到超過 limit memory, 會被 OOM 機制砍掉.
- request cpu 太小的話, 有可能 schedule job 耗用的 cpu 反而比較高, 造成效率變差.
- limit memory 至少是 request memory 的一倍大, 才不會被塞進剩餘空間太小的 node 然後 OOM 被宰.
- nodejs 可能有 memory leak 狀況, memory 可能會越吃越多(無法被 gc), 最後被 OOM 砍掉.
- nodejs memory leak 越嚴重, cpu 耗用越高, 有可能卡到 limit cpu 導致卡卡的慢.
- java / nodejs 服務啟動時可能會吃大量 memory, 然後才 gc 放掉, limit memory 就得觀察後再提高.



Cloud Features
- AWS
  - node instance type 用 t 系列可以 cpu burst (use credit or $$), 必要的時候 limit cpu 可以拉很高來用.
- GCP
  - request minimum
    - cpu 50m
    - memory 52Mi
  - resources cpu:memory 比例有最大上限 1:6.5
- Azure
  - TBD


Azure
- cpu
  - request 要看服務是用什麼服務/架構寫的, 太少的話可能 pod 不會在 1 分鐘內 ready, 像是 java.
  - limit 要觀察服務量有多大而設定, 或是服務本身的機制耗用 cpu 高的話, limit 也拉高備用.
  - go
    - request
      - 50m
    - limit
      - 200m or more
  - nodejs / typescript
    - request
      - 100m
      - or more for pod ready in 1min
      - or less for low cpu resource use after startup
    - limit
      - 500m
  - java / kotlin / scala
    - request
      - 200m
      - or more for pod ready in 1min
      - or less for low cpu resource use after startup
    - limit
      - 1
      - 還是有可能 1 分鐘內 pod 沒來得及 ready, 得調整 deployment 加長 ready 偵測時間
        - spec.template.spec.containers.livenessProbe.initialDelaySeconds: 60
        - spec.template.spec.containers.readinessProbe.initialDelaySeconds: 60

- memory
  - request 通常會設定為比目前用量小一階的基本量.
  - limit 則是會設定為比目前用量大一階, 得花些時間觀察狀況持續更新.

% kubectl top pod | grep foobar-deploy foobar-deploy-8487bddd77-cl5br 18m 365Mi foobar-deploy-8487bddd77-pmpm4 43m 343Mi foobar-deploy-8487bddd77-sfdtc 19m 299Mi foobar-deploy-8487bddd77-sl5s9 21m 605Mi foobar-deploy-8487bddd77-sr5kc 21m 618Mi
- request - 256Mi - limit - 768Mi
% kubectl top pod | grep blahblah-deploy blahblah-deploy-6fc6dd8c97-5txhc 25m 263Mi blahblah-deploy-6fc6dd8c97-7s8jb 26m 287Mi blahblah-deploy-6fc6dd8c97-9dc4z 25m 199Mi blahblah-deploy-6fc6dd8c97-bc7kf 26m 330Mi blahblah-deploy-6fc6dd8c97-bqwwf 26m 329Mi blahblah-deploy-6fc6dd8c97-dgj22 24m 283Mi blahblah-deploy-6fc6dd8c97-gjftr 26m 260Mi blahblah-deploy-6fc6dd8c97-kgmf4 24m 279Mi blahblah-deploy-6fc6dd8c97-nl667 25m 217Mi blahblah-deploy-6fc6dd8c97-nqbqb 28m 266Mi blahblah-deploy-6fc6dd8c97-pjfs9 33m 220Mi blahblah-deploy-6fc6dd8c97-qbslb 26m 527Mi blahblah-deploy-6fc6dd8c97-sf4hc 38m 261Mi blahblah-deploy-6fc6dd8c97-tn5ch 27m 392Mi blahblah-deploy-6fc6dd8c97-wg2qs 25m 258Mi
- request - 128Mi - limit - 512Mi or 768Mi - 因為 pod 數量夠多, 所以少數超過 512Mi 的情況可以接受設定 512Mi 被 OOM 砍掉換人做. - 但如果是一次處理大量資料的 pod, 就不能發生被中途砍掉的狀況, 得設定 768Mi 甚至更多.

2024年6月6日 星期四

Terraform - aws_rds_proxy 接 RDS PostgreSQL 的 init_query 指令

在 Terraform 的文件 db_proxy_default_target_group 只有提供 MySQL 的使用範例:

resource "aws_db_proxy" "example" {
  name                   = "example"
  debug_logging          = false
  engine_family          = "MYSQL"
  idle_client_timeout    = 1800
  require_tls            = true
  role_arn               = aws_iam_role.example.arn
  vpc_security_group_ids = [aws_security_group.example.id]
  vpc_subnet_ids         = [aws_subnet.example.id]

  auth {
    auth_scheme = "SECRETS"
    description = "example"
    iam_auth    = "DISABLED"
    secret_arn  = aws_secretsmanager_secret.example.arn
  }

  tags = {
    Name = "example"
    Key  = "value"
  }
}

resource "aws_db_proxy_default_target_group" "example" {
  db_proxy_name = aws_db_proxy.example.name

  connection_pool_config {
    connection_borrow_timeout    = 120
    init_query                   = "SET x=1, y=2"
    max_connections_percent      = 100
    max_idle_connections_percent = 50
    session_pinning_filters      = ["EXCLUDE_VARIABLE_SETS"]
  }
}

這邊 init_query 是用 “SET x=1, y=2” 當作 proxy 連上 DB 的測通指令, 但是 MySQL 的 SET 指令跟 PostgreSQL 的 SET 指令用法不同, 所以直接把這個範例給 PostgreSQL 用的時候會噴錯誤:

proxy log:
- [INFO] [dbConnection=1140488035] The database connection closed. Reason: An internal error occurred.

DB log:
- ERROR: syntax error at or near "=" at character 11
- STATEMENT: SET x=1, y=2

(以上來自 CloudWatch Log Groups, DB 跟 DB proxy 都有設定送出 log 到這邊)

伸進去 PostgreSQL DB 手動執行指令看看:

postgres=> SET x=1, y=2;
ERROR:  syntax error at or near "="
LINE 1: SET x=1, y=2;
                  ^
postgres=> SET x=1;
ERROR:  unrecognized configuration parameter "x"
postgres=>

確認是 SET 指令造成錯誤.

Google 查了幾下也是有一些回報同樣的問題, 解法幾乎都是把 init_query 拿掉, 但是這樣就少了一個 proxy 連入 DB 後, 測通 DB 是否有正常反應的機制.

所以找個簡單的指令替代 SET 就解決了:

init_query = "VALUES (1,2)"

AWS - IAM Role with Policy

AWS 的 IAM Role 跟 Policy 有兩種連接方式:
- Role 內嵌 Policy.
- Role 和 Policy 是各自建立, 然後再接起來(attach)用.

以 Policy 編修來說, 前者就只能在 portal 上面 CRUD, 後者在 Policy 本身的 portal 介面還可以看 permission 檢查, 歷次編修版本與控管, 相同的 Policy 還可以接到多個 Role 共用, 後來我也盡量都用後者.

不過後者在 Terraform 的寫作上有需要注意的地方, 一般寫法如下:

resource "aws_iam_policy" "this" {}
resource "aws_iam_role" "this" {}
resource "aws_iam_role_policy_attachment" "this" {
  depends_on = [
    aws_iam_role.this,
    aws_iam_policy.this
  ]
}

在 terraform apply 的時候不成問題, 但是在 terraform destroy 會發生 race condition: Policy 還沒從 Role 拆出來, 上面這個寫法會造成 aws_iam_policy 跟 aws_iam_role 同時進行 destroy, 在刪除 aws_iam_policy 就會噴錯誤訊息, 說 Policy 還接在 Role 上面所以不能被砍掉.

雖然再執行一次 terraform destroy 就過了(錯誤是在砍 aws_iam_policy 的時候噴的, 但同時砍 aws_iam_role 的動作有被完成), 但是這樣對於砍站跑路就不夠絲滑.

簡單解決的方式就是在 aws_iam_role 裡面加一個 depends_on aws_iam_policy:

resource "aws_iam_role" "this" {
  ...

  depends_on = [
    aws_iam_policy.this
  ]
}

這樣子在 destroy 的時候, aws_iam_role 就會先被刪除(無論 Policy 拆出來了沒), 再刪除 aws_iam_policy 就不會卡住了.

然後第一個方式在 Terraform 有個地雷, 在 Role 裡面內嵌 Policy 大概是這樣寫:

resource "aws_iam_role" "this" {
  ...

  inline_policy {
    name = "Role-foobar-Policy"
    ...
  }
}

當不要用 inline_pocily 的時候, 把這段刪除成這樣:

resource "aws_iam_role" "this" {
  ...
}

然後 terraform apply 的時候, diff 並沒有出現 - 掉 inline_policy 這塊的訊息, 實際上 Terraform 真的沒做這個刪除, 在 portal 是還看得到 inline_policy 的存在, 得在這邊手動砍掉才算沒了.


隱欌地雷: AWS IAM 有好幾個拆連接的動作會產生 race condition, 表面上 API 回應 ok, 但是實際上裡面還在慢慢斷開, 沒那麼快拆完...