AutoScalingグループにライフサイクルフックを設定し、スケールアウト時に、Lambda関数を実行してみます。
このLambda関数では、ライフサイクルフックで保留状態のインスタンスにSSH接続して、コマンドを実行するようにします。
コマンド実行後は、保留を解除してライフサイクルを続行します。
ライフサイクルフックの詳細は下記URLを参照。
https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/lifecycle-hooks.html
1.lambda関数 の用意
AutoScalingでインスタンスが起動したときに実行する lambda関数を作成します。
ソースコードは以下のとおり。
paramiko をLambdaで使用する方法は、こちらの記事を参照。
import boto3 import paramiko def scaleout_handler(event, context): # instance-id -> private ip address print "get ip" ec2 = boto3.resource('ec2') instance = ec2.Instance(event['detail']['EC2InstanceId']) ip = instance.private_ip_address print "ip=" + ip # Download private key file from S3 bucket print "get key from s3" s3 = boto3.client('s3') s3.download_file('blue21.dev.local','ssh_key.pem', '/tmp/ssh_key.pem') # ssh connect print "connecting ssh" k = paramiko.RSAKey.from_private_key_file("/tmp/ssh_key.pem") c = paramiko.SSHClient() c.set_missing_host_key_policy(paramiko.AutoAddPolicy()) c.connect( hostname = ip, username = "centos", pkey = k ) print "connected" # execute command commands = [ "ps -ef" ] for command in commands: print "Executing {}".format(command) stdin , stdout, stderr = c.exec_command(command) print stdout.read() # lifecycle continue print "lifecycle continue" as_client = boto3.client('autoscaling') res = as_client.complete_lifecycle_action( LifecycleHookName=event['detail']['LifecycleHookName'], AutoScalingGroupName=event['detail']['AutoScalingGroupName'], LifecycleActionToken=event['detail']['LifecycleActionToken'], LifecycleActionResult='CONTINUE' ) return { 'message' : "scaleout function finished" }この Lambda関数では以下の処理を実行します。
(1) イベント情報のインスタンスIDからプライベートIPを取得
(2) S3バケットからSSH秘密鍵(ssh_key.pem)をダウンロード
(3) プライベートIPのサーバにsshログイン
(4) ps -ef コマンドを実行
(5) lifecycle-hook で待機状態になったインスタンス状態を続行する。
このLambda関数が受信する LifecycleHook のイベント情報は以下のとおり。
{ "account": "xxxxx", "region": "us-east-1", "detail": { "EC2InstanceId": "i-03e42db2057f658b0", "AutoScalingGroupName": "centos7_scale_test", "LifecycleActionToken": "d9436277-fcbc-4a41-b197-fe4c044aeb7f", "LifecycleHookName": "scaleout_fook", "NotificationMetadata": "a,b,c", "LifecycleTransition": "autoscaling:EC2_INSTANCE_LAUNCHING" }, "detail-type": "EC2 Instance-launch Lifecycle Action", "source": "aws.autoscaling", "version": "0", "time": "2018-02-11T03:47:27Z", "id": "5b94f10c-5b57-d22f-96d1-99e914f3ba0b", "resources": [ "arn:aws:autoscaling:us-east-1:xxxxx:autoScalingGroup:1179ba6e-dce9-465e-ab4f-45c02ccab751:autoScalingGroupName/centos7_scale_test" ] }
AWSへのデプロイに使用する template.yaml は以下のとおり。
関数名は、ScaleoutFunction にしました。
AWSにデプロイする方法は、こちらの記事を参照。
AWSTemplateFormatVersion: '2010-09-09' Description: scaleout lifecycle hook Transform: AWS::Serverless-2016-10-31 Resources: ScaleoutFunction: Type: AWS::Serverless::Function Properties: CodeUri: . FunctionName: ScaleoutFunction Handler: scaleout_function.scaleout_handler MemorySize: 128 Role: arn:aws:iam::xxxxx:role/Lambda01_Role Runtime: python2.7 Timeout: 10 VpcConfig: SubnetIds: - subnet-2ea4d166 SecurityGroupIds: - sg-bbf176df
また、S3からファイルをダウンロードするので VPCエンドポイントも使用します。
Lambda関数が使用するサブネットのルーティングテーブルは下図のようになります。
2.起動設定の用意
起動設定を作成します。
名称は、"launch-centos7-02" にしました。
AMIは CentOS7 を使用します。
プライベートIPのみ使用して、パブリックIPは設定しません。
3.AutoScalingグループの用意
AutoScalingグループを作成します。
名称は、"as-group-01" にしました。
[ターゲットグループ]の[希望],[最小]は 0 にし、[最大]は 1 にしてます。
あとで、動作確認するときに、[希望],[最小]を 1 にします。
[サブネット]は、Lambdaと同じプライベートサブネットを使用します。
3.ライフサイクルフックの設定
上記で用意した AutoScalingグループにライフサイクルフックを定義します。
名称は、"hook-scaleout" にしました。
[ライフサイクルフックタイプ]は、”インスタンスの作成”を選択して、インスタンス作成時にフックされるようにします。
4.CloudWatchEvent の設定
ライフサイクルフック発動時に、Lambda関数を実行するイベントのルールを定義します。
[イベントソース]
サービス名 ⇒ AutoScaling
イベントタイプ ⇒ Instance Launch and Terminate
特定のインスタンスイベント ⇒ EC2 Instance-launch Lifecycle Action
特定のグループ名 ⇒ as-group-01
[ターゲット]
Lambda関数
ScaleoutFunction
名前 ⇒ rule-scaleout
状態 ⇒ 有効
5.動作確認
AutoScaling でスケールアウトして、ライフサイクルフックの動きを見てみます。
S3バケットにSSH秘密鍵を置いておきます。
[root@centos702 lambda4]# aws s3 cp /root/ssh_key.pem s3://blue21.dev.local/ upload: ../ssh_key.pem to s3://blue21.dev.local/ssh_key.pem
ターゲットグループの[希望][最小]に1を設定して、スケールアウトします。
しばらくするとEC2インスタンスが起動します。
ライフサイクルフックでEC2インスタンスが待機状態になっています。
このとき Lambda関数が実行されます。
Lambda関数が実行され、ライフサイクルの続行を指示すると、"保留:待機" から"実行中"になります。
[アクティビティ履歴]を見ると、"成功" になっています。
Lambda関数のログは以下のとおり。
"ps -ef" コマンドの実行結果が記録されています。
[root@centos702 lambda4]# aws logs get-log-events --log-group-name /aws/lambda/ScaleoutFunction --log-stream-name '2018/02/12/[$LATEST]45c4bec38f264a46bad65ccfebe8f2ce' --output=text --query "events[*].message" START RequestId: 637efafc-0f95-11e8-a1ec-fd427653aa45 Version: $LATEST get ip ip=10.0.20.20 get key from s3 connecting ssh connected Executing ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 9 01:38 ? 00:00:02 /usr/lib/systemd/systemd --switched-root --system --deserialize 20 root 2 0 0 01:38 ? 00:00:00 [kthreadd] root 3 2 0 01:38 ? 00:00:00 [ksoftirqd/0] root 4 2 0 01:38 ? 00:00:00 [kworker/0:0] root 5 2 0 01:38 ? 00:00:00 [kworker/0:0H] root 6 2 0 01:38 ? 00:00:00 [kworker/u30:0] root 7 2 0 01:38 ? 00:00:00 [migration/0] root 8 2 0 01:38 ? 00:00:00 [rcu_bh] root 9 2 0 01:38 ? 00:00:00 [rcu_sched] root 10 2 0 01:38 ? 00:00:00 [watchdog/0] root 12 2 0 01:38 ? 00:00:00 [kdevtmpfs] root 13 2 0 01:38 ? 00:00:00 [netns] root 14 2 0 01:38 ? 00:00:00 [xenwatch] root 15 2 0 01:38 ? 00:00:00 [xenbus] root 16 2 0 01:38 ? 00:00:00 [kworker/0:1] root 17 2 0 01:38 ? 00:00:00 [khungtaskd] root 18 2 0 01:38 ? 00:00:00 [writeback] root 19 2 0 01:38 ? 00:00:00 [kintegrityd] root 20 2 0 01:38 ? 00:00:00 [bioset] root 21 2 0 01:38 ? 00:00:00 [kblockd] root 22 2 0 01:38 ? 00:00:00 [md] root 27 2 0 01:38 ? 00:00:00 [kswapd0] root 28 2 0 01:38 ? 00:00:00 [ksmd] root 29 2 0 01:38 ? 00:00:00 [crypto] root 37 2 0 01:38 ? 00:00:00 [kthrotld] root 38 2 0 01:38 ? 00:00:00 [kworker/u30:1] root 39 2 0 01:38 ? 00:00:00 [kmpath_rdacd] root 40 2 0 01:38 ? 00:00:00 [kpsmoused] root 41 2 0 01:38 ? 00:00:00 [kworker/0:2] root 42 2 0 01:38 ? 00:00:00 [ipv6_addrconf] root 61 2 0 01:38 ? 00:00:00 [deferwq] root 116 2 0 01:38 ? 00:00:00 [kauditd] root 124 2 0 01:38 ? 00:00:00 [kworker/0:3] root 179 2 0 01:38 ? 00:00:00 [rpciod] root 180 2 0 01:38 ? 00:00:00 [xprtiod] root 246 2 0 01:38 ? 00:00:00 [ata_sff] root 248 2 0 01:38 ? 00:00:00 [scsi_eh_0] root 250 2 0 01:38 ? 00:00:00 [scsi_tmf_0] root 251 2 0 01:38 ? 00:00:00 [scsi_eh_1] root 253 2 0 01:38 ? 00:00:00 [scsi_tmf_1] root 255 2 0 01:38 ? 00:00:00 [kworker/u30:2] root 256 2 0 01:38 ? 00:00:00 [kworker/u30:3] root 268 2 0 01:38 ? 00:00:00 [bioset] root 269 2 0 01:38 ? 00:00:00 [xfsalloc] root 270 2 0 01:38 ? 00:00:00 [xfs_mru_cache] root 271 2 0 01:38 ? 00:00:00 [xfs-buf/xvda1] root 272 2 0 01:38 ? 00:00:00 [xfs-data/xvda1] root 273 2 0 01:38 ? 00:00:00 [xfs-conv/xvda1] root 274 2 0 01:38 ? 00:00:00 [xfs-cil/xvda1] root 275 2 0 01:38 ? 00:00:00 [xfs-reclaim/xvd] root 276 2 0 01:38 ? 00:00:00 [xfs-log/xvda1] root 277 2 0 01:38 ? 00:00:00 [xfs-eofblocks/x] root 278 2 0 01:38 ? 00:00:00 [xfsaild/xvda1] root 355 1 0 01:38 ? 00:00:00 /usr/lib/systemd/systemd-journald root 389 1 0 01:38 ? 00:00:00 /usr/lib/systemd/systemd-udevd root 436 1 0 01:38 ? 00:00:00 /sbin/auditd root 494 2 0 01:38 ? 00:00:00 [ttm_swap] root 516 2 0 01:38 ? 00:00:00 [edac-poller] root 551 1 0 01:38 ? 00:00:00 /usr/sbin/rsyslogd -n polkitd 553 1 0 01:38 ? 00:00:00 /usr/lib/polkit-1/polkitd --no-debug root 555 1 0 01:38 ? 00:00:00 /usr/lib/systemd/systemd-logind dbus 559 1 0 01:38 ? 00:00:00 /bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation chrony 563 1 0 01:38 ? 00:00:00 /usr/sbin/chronyd root 585 1 0 01:38 ? 00:00:00 /usr/sbin/gssproxy -D root 775 1 0 01:38 ? 00:00:00 /sbin/dhclient -1 -q -lf /var/lib/dhclient/dhclient--eth0.lease -pf /var/run/dhclient-eth0.pid eth0 root 840 1 0 01:38 ? 00:00:00 /usr/bin/python -Es /usr/sbin/tuned -l -P root 854 2 0 01:38 ? 00:00:00 [kworker/0:1H] root 963 1 0 01:38 ? 00:00:00 /usr/libexec/postfix/master -w postfix 964 963 0 01:38 ? 00:00:00 pickup -l -t unix -u postfix 965 963 0 01:38 ? 00:00:00 qmgr -l -t unix -u root 996 1 0 01:38 ? 00:00:00 /usr/lib/systemd/systemd-hostnamed root 1017 1 2 01:38 ? 00:00:00 /usr/sbin/crond -n root 1018 1 0 01:38 tty1 00:00:00 /sbin/agetty --noclear tty1 linux root 1021 1 0 01:38 ttyS0 00:00:00 /sbin/agetty --keep-baud 115200 38400 9600 ttyS0 vt220 root 1063 1 0 01:38 ? 00:00:00 /usr/sbin/sshd -D root 1084 1063 17 01:38 ? 00:00:00 sshd: centos [priv] centos 1087 1084 0 01:38 ? 00:00:00 sshd: centos@notty centos 1088 1087 0 01:38 ? 00:00:00 ps -ef lifecycle continue END RequestId: 637efafc-0f95-11e8-a1ec-fd427653aa45 REPORT RequestId: 637efafc-0f95-11e8-a1ec-fd427653aa45 Duration: 6824.96 ms Billed Duration: 6900 ms Memory Size: 128 MB Max Memory Used: 90 MB [root@centos702 lambda4]#
以下のように、AutoScalingグループ名、ライフサイクルフック名、インスタンスIDを指定してコマンドを実行します。
[root@centos702 ~]# aws autoscaling complete-lifecycle-action --lifecycle-action-result CONTINUE --instance-id i-0d11d4ff1f236cc75 --lifecycle-hook-name hook-scaleout --auto-scaling-group-name as-group-01