CodestarでLayerを作ろうとして粘ったがだめだった話


AWS CloudformationでLayerを作る際の障害

AWS Cloudformationは非常に便利なサービスである反面、痒いところに手が届かないサービスでもある。
lambda Layerは最たるもので、コードのアップロードの方法は今の所S3へのファイルアップロードしかサポートされていない。
AWS Lambda LayerVersion Content
ただ、Layerの素晴らしいところは、複数のlambdaで利用している機能の一部をモジュール化できるところだ。
これは非常に魅力的だが、予めS3にデータをアップロードしておかなければならない。

以下は、どうにかしてlayerをCloudformationで楽にできないかと悪戦苦闘してだめだった失敗談である。

悪あがき

状況

Codestarでプロジェクトを作成し、編集していた。途中でLayerが使いたくなった

所見

まず、一連のサービスについて当時は以下のように認識していた。

  • ymlに構造を記載する
  • CodeBuildで、buildspecに記載したunixコマンドを実行しているっぽい
  • $がついているのは変数っぽい?→変数であることを確認
  • ならば、他のUnixコマンドも動くかも?

echoを試してみる

変数っぽかった
逆説的に、ディレクトリの構造さえわかればS3のバケット名とキーを特定できるのでは?と考えた。

buildspec.yml
phases:
  install:
    commands:

      # Upgrade AWS CLI to the latest version
      - pip install --upgrade awscli
      - echo $S3_BUCKET

codebuild
aws-codestar-ap-northeast-1-<AccountID>-<ProjectName>-pipe

buildspecには、unixコマンドが記載されており、変数も実行できることが確認できた。また、CodeBuildのlog画面の上の方に、次のような変数を確認した。

log
CODEBUILD_SRC_DIR=codebuild/output/src780260603/src

こちらもechoで試してみると、ディレクトリが得られた。

buildspec.yml
- echo $CODEBUILD_SRC_DIR 
codebuild
codebuild/output/src780260603/src

lsコマンドを使ってみると、たしかにお目当てのファイルがあった。
-ls $S3_BUCKET
```

text: log
python1_dir
python2_dir
module_dir

では、これをどうにかしてtemplate.yml内に反映させられればできるのではないか?と考えて1時間ほど調べた。

sedの発見(笑)

そんな中、ふとbuildspec.ymlを見ると、次のような箇所があった。

buildspec.yml
sed -i.bak 's/\$PARTITION\$/'${PARTITION}'/g;s/\$AWS_REGION\$/'${AWS_REGION}'/g;s/\$ACCOUNT_ID\$/'${ACCOUNT_ID}'/g;s/\$PROJECT_ID\$/'${PROJECT_ID}'/g' template-configuration.json

なんとなーく「文字列を置き換えているのかな?」と考えたらビンゴ。
sed コマンド
常識的なコマンドじゃないかって?こちとら去年Raspberry Piで初めてWidows以外のOSに触った筋金入りの初心者なんだよ。

早速使ってみたい。

sedを使って置換

どうもこうすれば置換できるらしい。

command
ed -i 's/<置換対象の文字列>/<置換したい文字列>/g;'

また、このままでは、$S3_BUCKETはテンプレート内でそのまま$S3_BUCKETとして置換されてしまう。そのため、シングルクオートではなく、ダブルクオートで囲む。
まくまくsed/awkノート
sed の置換パターンの中でシェルの変数を参照する

これでいけるはずだッ!!
と思うもエラーログ
text:log
No such key

どうも、S3にはそんなファイルがないようだ
ここからは何度試してもだめだった。

そもそも前提条件が違った

というかそもそも、さっきから見ていたのは、決してS3のディレクトリ(キー)構造ではなく、CodeBuild内に構築されているビルド環境内のディレクトリ構造であるという視点が抜けていた。
CodeBuild の概念

実質的にLayerのようなものは作れる

色々試したがだめだった。
それでも、共通(または類似)した処理のコード変更が発生した際、いちいち全てのファイルをチェックするのは面倒くさい。

そこで、落ち着いて今考えると次のようなコマンドをbuildspecのcommに記載すれば実質Layerみたいに使えることに気がついた。

directory
cloudformation ---- python1 -- first.py
                |
                |-- python2 -- second.py
                |
                --- common_modules -- common_module.py
buildspec
#略
 - cp ./common_modules/common_module.py ./python1/
 - cp ./common_modules/common_module.py ./python2/
#略

要するに手段と目的が逆転していたんですね

感想その他

結局やりたかたことはできなかったが、目的は達成できた。
また、なんだかんだCodeBuildやCloudformationの仕様にもなれることができたので良しとする。
なお進捗