#なぜ
- .ebextensionsで環境プロパティからインスタンスやボリュームにカスタムタグを追加している。管理ルールが変わりタグ更新が必要になったため、何気なく更新したらデプロイに失敗した。目的の環境プロパティをタグ以外の処で参照していた。
- シンプルに.ebextensionsを修正する何のことでもないことだが、保守担当に説明すると承認が必要のこと。これは時間がかかりそうだ。
#遠回り
改善策でサーバ構成もプログラムも遠回りしてはいけない。根本原因をつぶすのがベストだ。しかし、
承認とリリースまで1~2ヵ月はかかりそうなことと、以前からLambdaのイベントトリガーを試してみたかったことがあり今回は遠回りをする。
Lambda
- LambdaのRoleは事前登録しておく
Python3.8
import json
import boto3
def lambda_handler(event, context):
evt = str(event)
print(evt) #json parseできない文字列が飛んでくるため
# eb-app, new-tag, old-tag //環境変数の利用をお勧め
apps = [
["app1", "newapp1", "oldapp1"],
["app2", "newapp2", "oldapp2"],
["app3", "newapp3", "oldapp3"],
...
...
]
newTag = ''
oldTag = ''
client = boto3.resource('ec2', region_name='ap-northeast-1')
if evt.find('EbUpdateEnvironmentCron') > 0:
#from cloudwatch cron EBインスタンスはすべてチェックしたい時
#EbUpdateEnvironmentCron: イベント名
for app in apps:
newTag = app[1]
oldTag = app[2]
update_ec2tag(client, oldTag, newTag)
else:
#from cloudtail event
#更新されたEB環境に絞る
for app in apps:
if evt.find(app[0]) > -1:
newTag = app[1]
oldTag = app[2]
break
if len(newTag) > 1:
update_ec2tag(client, oldTag, newTag)
else:
print('target not ')
return {
'statusCode': 200,
'body': json.dumps('OK')
}
#ec2タグ更新
def update_ec2tag(client, oldTag, newTag):
print(str(newTag))
newTags = [{'Key': 'Project', 'Value': newTag}]
instances = client.instances.filter(
Filters = [{'Name': 'tag:Project', 'Values': [oldTag]}]
)
for instance in instances:
hasTag = 0
for tag in instance.tags:
if tag['Key'] == 'Project': #調整対象タグ
hasTag += 1
elif tag['Key'] == 'elasticbeanstalk:environment-id': #Elastic Beanstalkのインスタンのみにしたい
hasTag += 1
if hasTag == 2:
client.create_tags(
Resources=[instance.instance_id],
Tags=newTags
)
#print(instance.instance_id)
update_voltag(instance, newTags)
#volumeタグ更新
def update_voltag(instance, ptags):
instId = instance.instance_id
print(instId)
for vol in instance.volumes.all():
print('Updating tags for {}'.format(vol.id))
vol.create_tags(Tags=ptags)
CloudWatch Events Rule
- 名前: EbUpdateEnvironment -> Lambdaのトリガーに追加
- イベントパターン
{
"source": [
"aws.elasticbeanstalk"
],
"detail-type": [
"AWS API Call via CloudTrail"
],
"detail": {
"eventSource": [
"elasticbeanstalk.amazonaws.com"
],
"eventName": [
"UpdateEnvironment"
]
}
}
#おまけ
イベントトリガーをSQSにすると
def lambda_handler(event, context):
for record in event['Records']:
pval = record["body"] #ここにElastic Beanstalkのアプリ名
print(str(pval))
イベント発行
例え、zabbixで環境更新を検知したとしてアクションで設定
Elastic Beanstalkのデプロイ -> zabbixでアイテムで更新検知&アクション(SQSキュー生成) -> Lambda実行
zabbixアイテム例:https://qiita.com/mkawanee/items/66fb507ab9bd53638f58
/usr/bin/aws sqs send-message --queue-url https://sqs.ap-northeast-1.amazonaws.com/12345678/infra-modify-tag \
--region ap-northeast-1 --profile awsX --message-body {EVENT.NAME}
参照
#追記
CloudWatch EventでEBの環境名を拾って判断しているが、APIからはEnvironmentIdを使うため、環境名が入らない。EnvironmentNameをパラメータに追加すると、「'errorCode': 'InvalidParameterValueException'」になる。
とにかくログに環境名があればよいのでDescriptionに入れてみたらOK!
C#
var req = new UpdateEnvironmentRequest
{
EnvironmentId = "e-xxxxxx",
Description = "env-name-xxx",
OptionSettings = {options}
};