Study Notes - AutoScaling Lifecycle and Introduce


上一次 Basic Concept of AutoScaling 筆記之後,接著整理以下:

  • AutoScaling - Lifecycle
  • AutoScaling 導入新的系統,過程遇到的問題與心得。

AutoScaling - Lifecycle

下圖是官方文件的 AutoScaling Lifecycle 流程圖。整個流程在描述的都是 EC2 Instance 在 ASG 裡面生命週期的狀態,描述對象是 EC2 Instance,控制流程的是 ASG。流程中每個方匡是資源、圓角則是狀態、有兩個 Block 屬於 Lifecycle Hooks

依照主次分別,整理每個顏色的意思:

  • 深黃色:AWS Resource -> EC2 and AutoScaling 兩種
    • 不在 ASG 裡的 EC2
    • 由 ASG LC 建立的 EC2
    • ASG 本身,可以想像是一個 Controller
  • 深藍色:EC2 Instance 的主要狀態,可以說成是生與死兩種狀態
    • 生: InService - 服務中
    • 死: Terminated - 因為不健康或者 Scale In 已經被刪除的 Instance
  • 淺黃色:離開 ASG 、暫時離開 ASG 兩種裝換過程的狀態
    • 離開 ASG: Detaching -> Detached -> EC2 Instance (自由身)。EC2 Tag 裡面不再有 aws:autoscaling:groupName 這個 Key.
    • 暫時離開 ASG: Entering Standby -> Standby (暫時脫離 ASG,不在線上服務),可以再回去線上服務,會轉入 Pending
  • 淺藍色:EC2 Instance 生死的轉換過程,像是
    • 進入 InService 之前的 Pending
    • 進入 Terminated 之前的 Terminating
    • 轉換生死過程的 Lifecycle Hooks,可以執行額外的任務,後面描述。

幾個常見的狀況:

  • ASG: Scale Out
  • ASG: Scale In
  • EC2: Attach to ASG
  • EC2: Detach from ASG
  • EC2: Enter Standby

Lifecycle Hooks 基本概念

Lifecycle Hooks 可以讓主流程有些客製化的動作,最常見的應用場景有:

  • 機器要 Terminate 之前
    • 狀態變成 Terminating:Wait: 這時候執行自訂的 script or actions
      • 把 Log 備份到其他地方,像是 S3
      • 驅動 Lambda ,把狀態 persistent 到 DB or Storage
    • 執行完後告訴 ASG 可以繼續 Terminating:Processed,狀態將切回 Terminated
  • 機器進入 InService 之前
    • 狀態變成 Pending:Wait: 這時候執行自訂的 script or actions
    • 安裝需要的工具
      • 安裝最新版的 Application
      • 配置 application
    • 執行完後告訴 ASG 可以繼續 Pending:Processed,狀態進入 InService

Lifecycle Hooks 有都會先進入 XXXX:Wait 狀態,這時候 ASG 可以透過 CloudWatch Event、SNS、SQS 驅動事件,執行特定任務。

Lifecycle Hook 基本應用

我用 SNS 當作 Event Driven, Lambda 當作 handler,畫了簡單的流程圖如下:

圖中為了方便描述,我都用 AWS CLI 做說明,實務上可能需要換成用 SDK 寫。

建立 Lifecycle Hook 的準備

使用 Lifecycle-Hook 之前,有些東西要先準備好:

  • 設定一個 IAM Role 讓 ASG 可以打 SNS/SQS,Policy 選 AutoScalingNotificationAccessRole,如下:

  • 如果要用既有的 IAM Role,那就要在 Trust Relationship 裡的 Principal 加入 autoscaling.amazonaws.com
  • 建立 SNS Topic,裡面 Subscribe Lambda。
    • 不要直接在 SNS 裡 Subscribe SQS ,會打不到
    • SQS 直接在建立 hook 時,把 Target ARN 指定 SQS ARN
  • 透過 CLI or SDK 建立 Lifecycle Hooks,底下的例子建立 Hooks 給 Scale Out / In:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
## Scale Out, target to SNS
aws autoscaling put-lifecycle-hook \
--lifecycle-hook-name ${SCALE_OUT_HOOK} \
--auto-scaling-group-name ${ASG_NAME} \
--lifecycle-transition autoscaling:EC2_INSTANCE_LAUNCHING \
--notification-target-arn ${SNS_ARN} \
--role-arn ${NOTIFY_ROLE}
## Scale Out, target to SQS
aws autoscaling put-lifecycle-hook \
--lifecycle-hook-name ${SCALE_OUT_HOOK} \
--auto-scaling-group-name ${ASG_NAME} \
--lifecycle-transition autoscaling:EC2_INSTANCE_LAUNCHING \
--notification-target-arn ${SQS_ARN} \
--role-arn ${NOTIFY_ROLE}
## Scale In, target to SNS
aws autoscaling put-lifecycle-hook \
--lifecycle-hook-name ${SCALE_IN_HOOK} \
--auto-scaling-group-name ${ASG_NAME} \
--lifecycle-transition autoscaling:EC2_INSTANCE_TERMINATING \
--notification-target-arn ${SNS_ARN} \
--role-arn ${NOTIFY_ROLE}

建立好之後,查看目前有哪一些 hook (可以有多個),會發現有趣的東西。下面的例子有:

  • 有兩個 Scale-Out Hooks,個別的 Target ARN 有 SNS, SQS
  • 有一個 Scael-In Hook, Target ARN to SNS
  • 另外還有 CodeDeploy 建立的 Hooks
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
aws autoscaling describe-lifecycle-hooks \
--auto-scaling-group-name ${ASG_NAME}
{
"LifecycleHooks": [
{
"GlobalTimeout": 60000,
"HeartbeatTimeout": 600,
"AutoScalingGroupName": "my-asg",
"LifecycleHookName": "CodeDeploy-managed-automatic-launch-deployment-hook-xxxxxxxx",
"NotificationMetadata": "xxxxxxx-b9ac-4c9b-ba13-yyyyyy",
"DefaultResult": "ABANDON",
"NotificationTargetARN": "arn:aws:sqs:ap-northeast-1:528078681758:razorbill-ap-northeast-1-prod",
"LifecycleTransition": "autoscaling:EC2_INSTANCE_LAUNCHING"
},
{
"GlobalTimeout": 172800,
"HeartbeatTimeout": 3600,
"RoleARN": "arn:aws:iam::123456789088:role/ASG-Hooks",
"AutoScalingGroupName": "my-asg",
"LifecycleHookName": "scale-in-hook-sns",
"DefaultResult": "ABANDON",
"NotificationTargetARN": "arn:aws:sns:ap-northeast-1:123456789088:ASG-Notification",
"LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING"
},
{
"GlobalTimeout": 172800,
"HeartbeatTimeout": 3600,
"RoleARN": "arn:aws:iam::123456789088:role/LetSSL-ASG-Hooks",
"AutoScalingGroupName": "my-asg",
"LifecycleHookName": "scale-out-hook-sqs",
"DefaultResult": "ABANDON",
"NotificationTargetARN": "arn:aws:sqs:ap-northeast-1:123456789088:ASG-Lifecycle-Hook",
"LifecycleTransition": "autoscaling:EC2_INSTANCE_LAUNCHING"
},
{
"GlobalTimeout": 172800,
"HeartbeatTimeout": 3600,
"RoleARN": "arn:aws:iam::123456789088:role/ASG-Hooks",
"AutoScalingGroupName": "my-asg",
"LifecycleHookName": "scale-out-hook-sns",
"DefaultResult": "ABANDON",
"NotificationTargetARN": "arn:aws:sns:ap-northeast-1:123456789088:ASG-Notification",
"LifecycleTransition": "autoscaling:EC2_INSTANCE_LAUNCHING"
}
]
}

處理 Lifecycle Hook

設定好 Lifecycle Hook 之後,透過調整 ASG Desire,如果順利就會收到 SNS 打 Lambda 的 Hook Message 或者 SQS 也會收到,下圖個別事是透過 Lambda 顯示 SNS 送過來的 Lifecycle Hook Message,還有 SQS 收到的 Message:


Lifecycle Hook Message 中有以下重要的訊息,可以讓 Handler 作為接續動作的參考:

  • LifecycleActionToken: 用來處理接續任務後,告訴 ASG 可以繼續 Lifecycle 的 Token
  • LifecycleTransition: 用來判斷 Lifecycle 在哪裡,Handler 可以執行對應的任務。
  • EC2InstanceId: 可以知道是哪一台機器

Handler 依據需求執行對應的任務,像是安裝工具、配置軟體、般 Log 、寫狀態到 DB …. 等。

最後完成的時候再送一個 complete-lifecycle-action 就可以讓 hook 繼續走,透過 CLI 下如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
## 指定 EC2 Instance ID
aws autoscaling complete-lifecycle-action \
--lifecycle-action-result CONTINUE \
--instance-id ${INSTANCE_ID} \
--lifecycle-hook-name ${ASG_HOOK} \
--auto-scaling-group-name ${ASG_NAME}
## 用 LifecycleActionToken
aws autoscaling complete-lifecycle-action \
--lifecycle-action-result CONTINUE \
--lifecycle-action-token ${LC_ACTION_TOKEN} \
--lifecycle-hook-name ${ASG_SCALE_IN_HOOK} \
--auto-scaling-group-name ${ASG_NAME}

如果 Handler 事情不是在 Lambda 做,而是在 EC2 Instance 裡面,那就在 EC2 Userdata 裡放一段 script,機器起來的時候去 SQS 拿 Lifecycle Hook Message。

中斷 Lifecycle Hook

如果收到 Lifecycle Hook,正常流程是執行自己的 Handle Jobs,然後 CONTINUE,但不想讓他繼續走,那麼在 complete-lifecycle-action 時,把 result 改成 ABANDON 就可以了。

1
2
3
4
5
6
## ABANDON Lifecycle Hook
aws autoscaling complete-lifecycle-action \
--lifecycle-action-result ABANDON \
--lifecycle-action-token ${LC_ACTION_TOKEN} \
--lifecycle-hook-name ${ASG_SCALE_IN_HOOK} \
--auto-scaling-group-name ${ASG_NAME}

要注意 EC2 Instance 狀態會直接從 Pending:Wait 變成 Terminating

多個 Lifecycle Hook

一個 ASG 可以建立多個 Lifecycle Hook,表示有多個步驟要確認,那麼透過指定 Instance-ID Complete Hook 時,那麼要全部的 Hook 都被 Complete,流程才會繼續走。

1
2
3
4
5
6
7
8
9
10
11
aws autoscaling complete-lifecycle-action \
--lifecycle-action-result CONTINUE \
--instance-id ${INSTANCE_ID} \
--lifecycle-hook-name ${SCALE_OUT_HOOK_1} \
--auto-scaling-group-name ${ASG_NAME}
aws autoscaling complete-lifecycle-action \
--lifecycle-action-result CONTINUE \
--instance-id ${INSTANCE_ID} \
--lifecycle-hook-name ${SCALE_OUT_HOOK_2} \
--auto-scaling-group-name ${ASG_NAME}

注意事項

Lifecycle Hook 的等待時間預設為 一小時,表示 Hook 被發動後,ASG 就會等 Handler 去 Complete Lifecycle Action,預設等一小時!所以:

不要在 Production 做 Lab,不然 ASG Scaling Policy 發動後,如果忘了 Complete Lifecycle Hook,預設要一個小時才會生效。。。會等著開天窗。。。

Pending:WaitTerminating:Wait 預設等待時間是 一小時,意思是一小時之內,要告訴 ASG Hooks 的工作是否已經完成,否則一小時後,會自動往下一個流程走。

  • EC2 如果有掛 ELB,狀態會持續在 OutOfService
  • 即使透過 Desire 試圖讓他 Scale-In ,ASG 不會真的去砍他。
  • 正在 Wait 的 Hook,這時候如果砍掉 ASG Lifecycle Hook ,那麼就會解凍。

所以實驗完用不到的 Hook 要砍掉:

1
2
3
aws autoscaling delete-lifecycle-hook \
--lifecycle-hook-name ${ASG_HOOK} \
--auto-scaling-group-name ${ASG_NAME}

SQS 不要透過 SNS 遞送,要直接把 SQS ARN 寫在 --notification-target-arn 裡。

相關的 CLI

以下是幾個 AWS CLI 是常用的 ASG Lifecycle Hook,參考文件: aws autoscaling

導入 ASG 要考慮以及面臨的新問題

ASG 是 AWS 很重要,而且也非常實用的服務,特別是對開發,維運來講。但是 ASG 有一定的學習門檻與 AWS 基本的知識,我覺得至少要用過 EC2, SQS, SNS, VPC, Lambda, EC2 Userdata …. 較容易入門。

導入 ASG 馬上會面臨很多新的問題,我遇到的整理如下:

要能夠 Provision Stateless EC2

這其實是我同事遇到的問題。

沒有考慮 Provisioning 的狀況之下,就使用 ASG,才發現 Resource Provisioning 要花不少時間,影響專案時程。

實際上 Provisioning 要思考的事情不少,面向廣泛,技術複雜度高。通常需要有經驗的人比較容易完成。

詳細的心得請參閱 Resource Provisioning 的說明。

如何部署新的應用程式?

因為 AutoScaling 的機器都是動態的,所以部署的流程與方法都要重新考慮。

CI 流程:

  • 如果是直接透過 Jenkins 把 Build 好的 Artifacts 丟到機器,這樣的流程就要重新思以下方法:
    • 把 Build 好的 Artifacts 放到 S3,然後 EC2 Userdata 開機時自動下載安裝
    • Maintain 一份 ASG 線上機器的清單,這份清單必須是動態的。

部署方法:

  • 透過 AutoScaling 更新 Launch Configuration (LC) 部署:
    • 更新 LC,然後透過調整 Desire Size 大小,先放一樣的數字後,等新機器 Ready 後,還原原本大小
    • 建立新的 ASG,上同樣的 ELB,完成後砍掉舊的 ASG
    • 建立新的 ASG + LC + ELB,可以使用 CloudFormation
  • 只更新應用程式,不更換 EC2
  • 設計 Rollback 流程
  • 考慮 Blue-Green Deployment
    • 需要先有 EC2 的 Provisioning
    • 可以考慮用 CloudFormation or Terraform Provision 整個 Stack

CloudFormation 的整理:

如何取得機器的資訊?

在前一段提到 Maintain 一份 ASG 上機器的清單,主要是部署或者維護過程中,程式或者人可能會需要知道特定機器,甚至要進去機器看狀況,傳統沒有 ASG 的時候,是靠機器的名字作識別與溝通,ASG 就不會有這樣的概念,所以需要維護一份自己的清單。

但是我覺得理想的狀況之下,使用 ASG 的機器不應該,也不需要知道特定的機器。

這段我想提的其實就是 Whitepapter: Architecting for the Cloud 裡面的 Service Discovery,要開發一個服務,用來提供這些資源的資訊,讓其他服務可以查詢。這個服務自己就是批次更新 Resource 資訊,擔心資訊不夠即時,可以提供一個 refresh 的參數提供即時更新。

如何監控?如何蒐集 Log ?

同樣的,機器是動態的,所以監控的指標 (Metric) 將會是動態的,蒐集 Log 的方式也是動態的。

監控指標關係著 SLI (Service Level Indicator) 的定義,

SLI 一詞出自 Site Reliability Engineering: How Google Runs Production Systems,另外還有 SLO (Service Level Objective),和最常見的到 SLA (Service Level Agreement)

監控指標與 Log 蒐集可以使用 CloudWatch Log,詳細的說明參閱 Study Notes - CloudWatch 的整理。

線上發現異常如何處理?

如何發現異常 是一個議題,所以前一段的監控機制與 Log 蒐集就很重要。設計容易讓維運人員了解的 Metric 就很重要。

上線後如何 Operation?

定義的有以下:

  • 異常處理流程
  • OS Patch - AMI Maintain
  • Service Capacity (Scale Up or Scale Out)
  • 系統權限的調整
  • Backup and Recovery
  • Cost and Budget
  • Hardware Failure

教育訓練

ASG 需要適度的教育訓練,針對 Developer, Operator 直接就是做 Lab ,讓大家可以馬上體驗感覺。前面提到的觀念,要不斷的跟內部洗。

結論

不要為了 AutoScaling 而 AutoScaling,了解他適合的場景、使用的條件、思考 Provisioning 、部署、監控、維運等情境。

要特別強調的是,AutoScaling 裡的機器是 動態 改變的,所以傳統固定資源的觀念全部要重新思考,不管是架構、部署,監控、流程、還是溝通方式,都要重新調整。

然後思考 ASG 的目的是什麼?他帶來的好處在哪?

如果上線前把功能做好是 0-1 的過程,那麼上線後就是 1-99 的過程。

延伸閱讀

參考資料


Comments