#目的
CodeStarで作成したプロジェクトについて、
- yamlファイルを分割し、
- そのファイルを整理し、
- かつ
buildspec.yml
の記述を短くする。 - その上で、テンプレートが増えてもできる限りコマンドが増えないようにする。
#まえがき
CodeStarを使うと、CodeBuildとCloudFormationとを使ってYamlファイルで1AWSリソースを配置することができ、しかもそれらをgitで管理できる環境を自動構築してくれるため、非常に便利だ。しかし、リソースが増えていくと、どうしてもテンプレートファイルが長くなりやすく、可読性が下がってしまう。
そんなときは、スタックのネストを使うと便利だ。
しかし、(当然のことだが)yamlファイルを分割すればするほどファイル数が増えてしまい、保守しづらくなってしまうほか、buildspec.yml
も冗長になってしまう。
#このディレクトリは汚い
./--- ParentStack.yml
|
|- buildspec.yml
|
|- template-configration.json
|
|- templatefile1.yml
|
|- functionFolder1
|
|- templatefile2.yml
|
|- functionFolder
|
(以下略)
#真面目にやろうとするとbuildspec.ymlはテンプレートが1つ増えるごとに2行ずつ増えていく。
build:
commands:
# Use AWS SAM to package the application by using AWS CloudFormation
#First, package child package
- >-
aws cloudformation package --templat template1.yml
--s3-bucket $S3_BUCKET --output-template export-template1.yml
- >-
aws cloudformation package --templat template1.yml
--s3-bucket $S3_BUCKET --output-template export-template1.yml
#Then, package parent stack
- >-
aws cloudformation package --template ParentStackFile.yml
--s3-bucket $S3_BUCKET --output-template $CODEBUILD_SRC_DIR/ExportFiles/ParentStackFile.yml
# Do not remove this statement. This command is required for AWS CodeStar projects.
# Update the AWS Partition, AWS Region, account ID and project ID in the project ARN on template-configuration.json file so AWS CloudFormation can tag project resources.
- 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
post_build:
commands:
- mv template-configuration.json ./ExportFiles/
- cd ExportFiles
artifacts:
type: zip
base-directory: ./ExportFiles
files:
# This file is used code pipeline.
- ParentStackFile.yml
# They are child stackes output.
- export-stack1.yml
- export-stack2.yml
#templates
- template-configuration.json
そこで、yamlファイルを分割しつつそのファイルを整理し、かつbuildspec.yml
の記述を短くしたい。
#結論
###ディレクトリ構造
以下のようなディレクトリ構造にする。
CodePipelineやCodeURIの指定等に応じて適宜変更すること。
./--- ParentStack.yml
|
|- ExportFiles---description.txt(このファイルはファイル名、ファイル形式を問わない)
|
|- buildspec.yml
|
|- template-configration.json
|
|- childTemplateFiles--- template1--- templatefile1.yml
| |
| |- functionFolder1(lambda関数のソースを含む場合)
|
|- template1--- templatefile2.yml
| |
| |- functionFolder2(lambda関数のソースを含む場合)
|
(以下略)
###親スタックのテンプレート
親スタックは、ネストするテンプレートについて以下のように記載する。
Resources:
#Nest stack
Stack1:
Description:
This is test.
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: './ExportFiles/export-templatefile1.yml'
Stack2:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: './ExportFiles/export-templatefile2.yml'
Parameters:
ProjectId: !Ref ProjectId
CodeDeployRole: !Ref CodeDeployRole
Stage: !Ref Stage
###buildspecの記述
buildspec.yml
を、以下のように記述する。
version: 0.2
phases:
install:
commands:
# Upgrade AWS CLI to the latest version
- pip install --upgrade awscli
#First, pack child packages
- cd childTemplateFiles
- |、
for file in `ls -1 ./*/*.yml`
do
echo "$file"
filename=`basename $file`
echo $filename
aws cloudformation package --template $file --s3-bucket $S3_BUCKET --output-template $CODEBUILD_SRC_DIR/ExportFiles/export-"$filename"
done
- cd ..
build:
commands:
# Use AWS SAM to package the application by using AWS CloudFormation
# This command replaces PATH to this build enviroment path
- sed -i "s|PATH|$CODEBUILD_SRC_DIR|g" ParentStackFile.yml
#Then, pack parent stack
- >-
aws cloudformation package --template ParentStackFile.yml
--s3-bucket $S3_BUCKET --output-template $CODEBUILD_SRC_DIR/ExportFiles/ParentStackFile.yml
# Do not remove this statement. This command is required for AWS CodeStar projects.
# Update the AWS Partition, AWS Region, account ID and project ID in the project ARN on template-configuration.json file so AWS CloudFormation can tag project resources.
- 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
post_build:
commands:
- mv template-configuration.json ./ExportFiles/
artifacts:
type: zip
base-directory: ./ExportFiles
files:
- '*'
#試行錯誤の内容
##コマンドが長すぎ
まず始めたのが、特にこのコマンドが長すぎるのでどうにかして短くすること。
aws cloudformation package --template ParentStackFile.yml --s3-bucket $S3_BUCKET --output-template $CODEBUILD_SRC_DIR/ExportFiles/ParentStackFile.yml
Yamlは改行の扱いが結構細かく決められている印象だったので探してみたらあった。2
どうやら、>-
とつければ良いらしい。これで長過ぎるコマンドが、次のように表記でき、見やすくなった。
#文頭に>-をつけることで、改行がスペースとして扱われる。
- >-
aws cloudformation package --template ParentStackFile.yml
--s3-bucket $S3_BUCKET --output-template $CODEBUILD_SRC_DIR/ExportFiles/ParentStackFile.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
はどうにもうまく行かなかった。まあいいかと思い、次へ
##子スタックをまとめてパッケージしたい
###子スタックをforでビルド
スタックをネストするとき、CodeStarの初期設定だと概ね以下のような流れで行う。(他にも様々なフェーズがあるが、ここでは割愛)
- install
- 最低限aws cliをアップデート。必要なら他のパッケージを入手
- build
-
aws cloudformation package
で子スタック→親スタックの順にパッケージ。
-
- artifact
- パッケージされたテンプレートを送信
スタックが一つのうちは良いのだが、テンプレートファイルが増えるとaws cloudformation package
コマンドをいくつも書かなくてはならず、非常に面倒だと思った。
ところで、テンプレートファイルはymlと決めていることだし、forコマンドで.ymlファイルだけを検索し、ビルドできるのでは?と考えた。
そこで、unixコマンドのfor
について調べたところ、このサイト3からちょうど良さそうなものが見つかったため、次のように書き換えてローカルで実行した。
for var in `ls -1 *.yml`
> do
> echo $var
> done
template1.yml
template2.yml
問題は、buildspec.yml
内での記述だが、先程のページから2次のように記載すれば良いことがわかった。4
- cd childTemplateFiles #やらなくても良いが、気分で入れた
- |
for file in `ls -1 ./*/*.yml` #cdしなかったらもう一つ階層を足す
do
echo "$file"
filename=`basename $file`
echo $filename
#カレントディレクトリに出力する。
aws cloudformation package --template $file --s3-bucket $S3_BUCKET --output-template $CODEBUILD_SRC_DIR/export-"$filename"
done
###子スタックをまとめる
子スタックのテンプレートのみをまとめたフォルダを作り、そこにファイルをまとめた。
ビルドすると、lambda関数のCodeURI
指定がうまく行かない。どうも、テンプレートファイルをパッケージするとき、そのテンプレートファイルがあるフォルダがカレントディレクトリとして認識されるようだ。
では、いっそのこと次のようにまとめてしまえばフォルダもスッキリする。
./--- ParentStack.yml
|
|- buildspec.yml
|
|- template-configration.json
|
|- childTemplateFiles--- template1--- templatefile1.yml
| |
| |- functionFolder1(lambda関数のソースを含む場合)
|
|- template1--- templatefile2.yml
| |
| |- functionFolder2(lambda関数のソースを含む場合)
|
(以下略)
###どうせならファイルの送信もforで回したい
これでも十分短くなったが、artifactフェーズで送信するテンプレートを指定しなければならないのは面倒だ。
そこで、Exportfileという空フォルダを作り、送信するファイルはそこにまとめることにした。
そこでbuildspecを以下のように編集して実行してみる。
- cd childTemplateFiles
- |
for file in `ls -1 ./*/*.yml`
do
echo "$file"
filename=`basename $file`
echo $filename
#ExportFileに出力する
aws cloudformation package --template $file --s3-bucket $S3_BUCKET --output-template $CODEBUILD_SRC_DIR/ExportFiles/export-"$filename"
done
- ls ./ExportFiles
ところが、このまま実行すると「フォルダがない」と言われる。lsしても見当たらないため、ビルド環境にフォルダが作成されていないようだ。
おそらく、S3はフォルダという概念がない5ため、空フォルダを作るとS3上でNull
に変換され、ビルド環境にフォルダが作成されないのではないかと考えられる。
なので、適当なファイルをExportFileにぶちこみ、もう一度実行するとSuccessfully packaged artifacts and wrote output template to file
となった。
###親スタックの変更
親スタックは、テンプレートファイルを以下のように記述することで依存関係を表現できた。
Resources:
#Nest stack
Stack1:
Description:
This is test.
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: './ExportFiles/export-templatefile1.yml'
Stack2:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: './ExportFiles/export-templatefile2.yml'
Parameters:
ProjectId: !Ref ProjectId
CodeDeployRole: !Ref CodeDeployRole
Stage: !Ref Stage
###ファイルの送信
最後に、送信するファイルを指定すれば完了だ。
最初は、以下のようなコマンドを試したが、全てダメだった。
#試し
artifacts:
type: zip
files:
zip:
- |
for file in `ls -1 ./ExportFiles/*.yml`
do
echo "$file"
filename=`basename $file`
echo $filename
#まあechoじゃだめだよね。filelistがrequiredだったのでls -1してみる
type: zip
files:
- `ls -1`
#だめです。いっそ
type: zip
files: .
#だめでした。
ここで、公式ドキュメント6を参照したところ、どうも次のようにシングルクオートで囲めば良いようだ。
#試し
artifacts:
type: zip
files:
zip:
- ./ExportFiles/*.yml
なぜかファイルが送信できない。post_build
なるフェーズがあるらしいので、ここでcd
を使ってみる。
#試し
post_build:
- cd ./ExportFiles
artifacts:
type: zip
files:
zip:
- ./*.yml
ところが、これを実行したところ、次のようなレスポンスが返ってきた。
[Container] 2019/03/24 10:20:34 Expanding ./*
[Container] 2019/03/24 10:20:34 Found 2 file(s)
どうも、カレントディレクトリを探索し、2つのymlファイル(ここではbuildspec.ymlとビルド前のParentStack.yml)を探し当てたようだ。
cdの代わりにbase-directoryを指定すると次のようになった。
#試し
post_build:
artifacts:
base-directory: Export
type: zip
files:
zip:
- ./*.yml
[Container] 2019/03/24 10:25:18 Expanding ./ExportFiles/*
[Container] 2019/03/24 10:25:18 Found 10 file(s)
これで成功したかと思ったが、template-configuration.json
も送信しなければならないため、コードを次のように変更したところ、成功した。
post_build:
commands:
- mv template-configuration.json ./ExportFiles/
- cd ExportFiles
artifacts:
type: zip
base-directory: ./ExportFiles
files:
- '*'
-
jsonでも記述できるが、非常に可読性が悪く書きづらい ↩
-
どうでも良い情報かもしれないが、変数をバッククォートで囲むと
Permission Denied
という結果が返ってくる。どいういうことだろうか? ↩ -
https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-spec-ref.html ↩