km_output

お勉強と趣味のアウトプット

【AWS】CloudWatch インサイトのクエリ結果をエクスポートできるの知らなかった。

CloudWatch インサイトのクエリ結果ってエクスポートできたんだwww

知らなくてびっくりした・・・。

それっぽいページ https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/CWL_ExportQueryResults.html

マネージメントコンソールの操作としては、[アクション]、[エクスポート - 個のクエリ結果(CSV)]

個の、は誤訳かな?「この(This)」だと思われる。

個人的にインサイトは下記場面でお世話になることが多めだったが、件数少ないからいつも目視してた。かなしみ。

  • 複数のLambdaログを横断検索

  • Lambdaエラーログの特定・抽出

  • Lambdaに割り当てたメモリごとの実行時間・使用メモリの推移調査

【AWS】LambdaでCloudWatchログをデコードしようとして手間取った話

とあるLambda(複数)を監視して、タイムアウトエラーが発生したらslack通知する力技構成を作成中のこと。

※構成の詳細は以下。

slack通知用Lambdaのトリガに、CloudWatch Logsを選択。

対象ログはタイムアウトエラー検出対象となる Lambda のログ。

メトリクスフィルターとして文字列「Task timed out after」を設定。

タイムアウトエラー検出したい Lambda でタイムアウトエラーが起こればslackへ通知される仕組み。

トリガであるCloudWatch Logsのログデータから Lambda 関数名拾おうと思ったら、まずログをデコードしないといけないっぽい。

qiita.com

下記のページを見つけて、これだ!!と思ったのも束の間、Python3とはコードの差分があるみたい。

inokara.hateblo.jp

結局は以下のようにデコード。めでたし、めでたし。

def lambda_handler(event, context):
    json_decode_data = decode_function(event['awslogs']['data']);
    print(json_decode_data); #デコードできていることを確認。
    logGroup_name = json_decode_data['logGroup'].rsplit("/", 1)
    lambda_function_name = logGroup_name[1] #ここでLambda関数名を取り出す

# CloudWatch Logsデータのデコード処理をする関数
def decode_function(data):
    # Base64デコードして解凍してデータを取得する
    decoded_data = base64.b64decode(data)
    json_data = json.loads(gzip.GzipFile(fileobj=BytesIO(decoded_data)).read())
    return json_data

そもそもだけど他によい通知方法あれば知りたいなあ。

【AWS】LambdaでEC2起動したくてmodify_instance_attributeと戯れた話

前提

Lambdaでインスタンスタイプ変更→EC2インスタンス起動、失敗したら他のインスタンスタイプへ変更して起動を試みる…という仕組み。

改修する機会があって動かしていたときのエラーと対処法をまとめる。

エラーと対処法

エラーその1

An error occurred (Unsupported) when calling the StartInstances operation: Your requested instance type (t3a.medium) is not supported in your requested Availability Zone (ap-northeast-1c). Please retry your request by not specifying an Availability Zone or choosing ap-northeast-1a, ap-northeast-1d.

→AZ未対応インスタンスタイプを指定するとこうなる。

上記は東京リージョンのAZ-1cでt3a.mediumを起動しようとした際のエラー。

AZ-aだとt3a.mediumで起動できるのだが。

インスタンスタイプのリストをAZごとに分けて、AZ-cのときt3aを指定しないようにすることで回避。

エラーその2

An error occurred (InvalidParameterCombination) when calling the ModifyInstanceAttribute operation: These parameters are mutually exclusive: attribute, ebsOptimized

→訳あってEBS最適化を無効化したかったが、書き方がアカン。

modify_instance_attributeに余計な引数を入れていたので消したら動いた。

        if instance_type == 't2.medium':
            ec2.modify_instance_attribute(
                Attribute='ebsOptimized', # この行が不要
                EbsOptimized={'Value': False},
                InstanceId=instance_id
            )

余談だが、EBS最適化を有効化したままだとEBS最適化をサポートしないインスタンスタイプでの起動ができなくなる。

dev.classmethod.jp

これに対応したくて、Lambdaのboto3ではどうやってEBS最適化の有効化/無効化をするんだろうと調べてたどり着いたのが modify_instance_attribute でしたとさ。

【AWS】boto3でS3操作するときclientとresourceの使い分けでハマった話

実現したいこと

  • boto3を使って Lambda からS3操作したい。

Lambda関数(ランタイムはPython3.8)で、AアカウントのS3バケットからBアカウントのS3バケットへデータをコピーしたい。

その時にオブジェクトACL付与が必要となり、単純にオブジェクトACL付与する場合とオブジェクトコピー時に権限付与する場合とで違いがあるのか検証していた。

コード

boto3.client('s3')boto3.resource('s3') で混乱したものの、以下のような違いがあると分かった。

明確に意識していなかったのでφ(._.)メモメモ

# S3バケット内のオブジェクトに対しオブジェクトACLを付与

s3resource = boto3.resource('s3')

object_acl = s3resource.ObjectAcl(s3bucket,s3key)

response = object_acl.put(ACL='bucket-owner-full-control')

~~~
# S3バケット内のオブジェクトをコピー

s3 = boto3.client('s3')

r = s3.copy_object(ACL='bucket-owner-full-control',Bucket=s3bucket_processing, Key=copy_s3key, CopySource={'Bucket': s3bucket, 'Key': s3key})

【AWS】LambdaをPython2→3へバージョンアップしようとした話

実現したいこと

  • AWS上の既存Lambda関数のランタイムをPython2.7→3.xへ更新したい

Python2.7がEOLになるためPython3.8にバージョンアップしたい。

ソースのどこを直せばよいか調査&検証しつつ手探りで進めるうちに、結局Lambda自体使わないことになったので調べた内容を記しておく。

試行錯誤あれこれ

  • まず既存LambdaについてPythonランタイム 2.7で動作確認OK。

Pythonのバージョンが2なので print(event) 時にUnicode形式を表す小文字のuがついている。初耳。

https://teratail.com/questions/228220 https://stackoverflow.com/questions/13940272/python-json-loads-returns-items-prefixing-with-u

コードはそのままに、Pythonランタイム 2.7 → 3.7 へ変更してみた。

  • StringIOエラー
[ERROR] Runtime.ImportModuleError: Unable to import module 'lambda_function': No module named 'StringIO'

外部モジュール'StringIO'が読み込めないようす。

解決方法:

Python2と3のパッケージの違い

qiita.com

以下のようにコードを修正。

from StringIO import StringIO → from io import StringIO

  • urllib.parse.unquote_plusらへんのエラー

Exception: module 'urllib' has no attribute 'unquote_plus'

teratail.com

書いてある通り、urllibモジュールにはurlencodeが存在しません。

そのため、関数を呼べずにエラーとなっています。

Python3系では、urllib.urlencodeはurllib.parse.urlencodeになっていますので、

そちらを使うようにすれば動くと思います。

解決方法:

今回は urllib.unquote_plus を使用していたので、以下のようにコードを修正。

urllib.unquote_plus → urllib.parse.unquote_plus

  • decodeでエラー

Exception: 'str' object has no attribute 'decode' for event~~~

ja.stackoverflow.com

おそらく、python2で書かれたプログラムをpython3で実行しようとされているのだと思います(strのdecodeはpython3にはないので)。

動かしたいのは以下で紹介されているTextGeneratorでしょうか。

https://karaage.hatenadiary.jp/entry/2016/01/27/073000

であればこのページが参考になるとおもいます。

https://qiita.com/betit0919/items/4fbba42de6df90bc7088#text-generatorの利用

解決方法:

Python3だと

urllib.parse.unquote_plus(string, encoding='utf-8', errors='replace')

らしい。

docs.python.org

というわけで以下のように修正。

urllib.parse.unquote_plus(String).decode('utf8') → urllib.parse.unquote_plus(String)

  • ioでエラー

Exception: name 'io' is not defined

from io import StringIO してから io.StringIO(data) みたいに使っているのが原因かな?と思い、以下のようにコードを修正してみる。

from io import StringIO → import io

エラーが変わった。

Exception: initial_value must be str or None, not bytes

www.monotalk.xyz

StringIO に import に関しては、import 文を以下の修正で問題ないと思いますが、文字列? byte? の内部処理でエラーになっているようです。

StringIO ではなく、ByteIO を使用する形で修正しました。

Python の Version が 3 であれば、BytesIO を使用する形に書き換えました。

もっといいやり方がありそうに思いますが、とりあえず動くことは確認できました。

以下のように修正してみる。

io.StringIO → io.BytesIO

とりあえずエラーはなくなった。

以下の手順が必要かと思ったけどLambdaの動作確認できてしまったので、以下は未検証。

  • Pythonランタイム 2.7 → 3.7 へバージョンアップ時、以下の手順で Lambda デプロイパッケージを作成する必要がある?

https://hacknote.jp/archives/48083/

  • PythonAWS Lambda デプロイパッケージ

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-python-how-to-create-deployment-package.html

今回対応したことまとめ

from StringIO import StringIO → from io import StringIO

io.StringIO → io.BytesIO

urllib.unquote_plus → urllib.parse.unquote_plus

12月1日にリラックマ検定を受けてきた話

リラックマ検定、だと・・・!?

長生きしていると、こんな検定にも出会うものである。

www.kentei-uketsuke.com

解答が公開されて復習も一通り終わり、家族からの視線も和らいだので書きしたためる。

試験対策

公式テキストの模擬問題がほぼそのまま出題、加えてデザインの並べかえ問題・ぬいぐるみの発売時期、該当テーマが問われた。

意外とぬいぐるみ系の出題が多かった。もっと勉強しておけばよかった・・・。

テーマ問題では似たようなデザインのテーマが選択肢に並んでいるため要注意。

マニアなら問題ないが、初見の人からするとポカーン状態になる水準。

当日のようす

東京会場にて初級・中級の併願ぼっち受験。

お友達同士、親子、パートナー同士などなど、ペア割を利用しているであろう受験者も多かった。

驚いたのが、併願受験者の多さ。

たまたま併願受験者が多い教室に割り当てられたのかもしれないが、教室の8割近くの人が中級も引き続き受けていた。

戦利品

受験者限定で当日配布されたクリアファイル。問題お持ち帰り用に最適だった。

f:id:km_tech:20191217221805j:plain
リラックマ検定_初級

中級は問題のレベルがややマニア向けに。ごちそうさまでした。

f:id:km_tech:20191217221600j:plain
リラックマ検定_中級

感想

「検定」と名のつくだけあって、そこそこいいお値段。試される愛。

そのうえ併願受験にしてしまったので、家族から正気を疑われるハメに。

合格者限定のグッズも販売される。すさまじき商魂。

合格発表が楽しみである。

【AWS】Lambdaで急にKMSエラー!?

都市伝説かと思っていた謎事象に遭遇した。

経緯

  • Lambda(その1)からLambda(その2)を非同期呼び出ししていた。

開発環境で検証していて、処理内容もログも異常なしだった。

1日かけて検証が終わり、何日か動かしてみようと思いその日は退勤。

  • 翌日、Lambda(その2)のメトリクスを見るとエラーが出ていた。

直近3時間のメトリクスは全てエラーだった!!

昨日から特に変更していないし、昨日まではログが出ていたのに・・・。

エラーログを見ようとしたら昨日19時過ぎたあたりからログが全く出ていない。

つまり、Lambda(その2)は実行されていないor処理冒頭でコケている可能性大。

ちなみにLambda(その1)は異常なし。

エラー内容

仕方がないのでLambda(その2)でテストイベントを作成してテスト実行。エラー内容は以下。

API アクションの呼び出しに失敗しました。エラーメッセージ: Lambda was unable to decrypt the environment variables because KMS access was denied. Please check the function's KMS key settings. KMS Exception: AccessDeniedExceptionKMS Message: The ciphertext refers to a customer master key that does not exist, does not exist in this region, or you are not allowed to access.

Lambda(その2)にアタッチしたロールにはKMSのフル権限つけている。昨日はこんなエラー出なかったじゃないか~。

と思いつつ、グーグル検索にすがる。

解決方法

前例があったのでその通りに対処した。

明確な原因は分からなかったが下記の記事の通りにしたらできた。

AWS Lambda関数の環境変数の復号エラーへの対処

「カスタマーマスターキーの使用」から適当なキーを選んで一旦保存し、再度 aws/lambda に戻して保存し直す

なんだこの謎事象・・・!とはいえ早期に解決できてよかった。

ちなみに、このLambdaはCloudFormationテンプレートを使って作成したけど何か関係あるのだろうか。。。