Study Notes - EC2 Auto Scaling - Lifecycle and Hooks


接著整理 EC2 Auto Scaling 中很重要的觀念:Lifecycle and Hooks

EC2 Auto Scaling 系列文章


EC2 Auto Scaling Lifecycle

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

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

  • 深黃色:AWS Resource -> EC2 and Auto Scaling 兩種
    • 不在 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
## 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


延伸閱讀

系列文章

站內延伸


Comments