☕️

ecspresso advent calendar 2020 day 5 - テンプレート記法

2020/12/05に公開

Amazon ECS のデプロイツールである ecspresso の利用法をまとめていく ecspresso Advent calendar 5日目です。

設定ファイルのテンプレート化

ecspresso の設定ファイル(YAML形式)、サービスとタスクの定義ファイル(JSON形式)は、実行時に kayac/go-config で処理されるテンプレートとして動作します。

デプロイする際の典型的なユースケースとして、イメージのタグをテンプレートに注入する例を示します。{{ must_env `TAG` }} の部分が、ecspresso 実行時の環境変数 TAG の値に置換されます。

{
    "containerDefinitions" : [
        {
            "name": "nginx",
            "image": "nginx:{{ must_env `TAG` }}",
            // ....
        }
    ],
    // ...
}

次のようなワークフローを実行することで、定義ファイルを編集せず、毎回のデプロイごとに個別のタグを持ったタスク定義を登録してサービスにデプロイできます。

  1. コンテナイメージをビルドして ECR に push し、デプロイごとに一意のタグをつける
    (リポジトリのタグやコミットハッシュを利用することが多いようです)
  2. 環境変数 TAG にその値を設定して ecspresso を実行する

利用できるテンプレート記法

ecspresso (go-config) は、実際には Go の標準パッケージである text/template を利用してテンプレートファイルをレンダリングし、その後に YAML/JSON としてパースします。ecspresso ではテンプレート関数として、次のものを用意しています。

env

"{{ env `NAME` `default value` }}"

環境変数 NAME が設定されていればその値を、設定されていなければ default value に置き換えます。

must_env

"{{ must_env `NAME` }}"

環境変数 NAME の値に置き換えます。もし実行時に環境変数が設定されていない場合、ecspresso は panic を起こして強制停止します。

意味のある値を定義せずに実行すると問題が起きるような値は must_env で定義しておくことで、意図しない状態でデプロイされることを防げます。

json_escape

"{{ must_env `JSON_VALUE` | json_escape }}"

値を JSON 文字列としてエスケープします。文字列として埋め込む場合にエスケープが必要な値("など)をエスケープしたい場合に利用します。

テンプレートTips

YAML や JSON としてなるべく壊れないように記述する

例として、config.yaml で region と cluster を変数化する場合を考えます。

素直にテンプレート記法を適用して次のように書いてしまうと、生の { がオブジェクトの開始と認識されてしまうため、テンプレート自体を正しい YAML として評価できなくなります。

region: {{ must_env `AWS_REGION` }}
cluster: {{ must_env `CLUSTER` }}

ecspresso で利用する場合は「テンプレートのレンダリング」→「YAML/JSONとしてのパース」の順で処理されるので問題はありませんが、ファイルをエディタで編集する場合などは整形に支障が出ることがあります。

次のようにクォートしておくと、YAMLとして正しい状態を維持できます。

region: '{{ must_env `AWS_REGION` }}'
cluster: '{{ must_env `CLUSTER` }}'

テンプレート記法と文法が競合する値を記述したい

Issue #32 より。

{{.ID}} という値自体を記述したい場合、{{ }} がテンプレートとして処理されてしまうため、直接記述することができません。

見た目が煩雑になりますが、文字列 {{.ID}} そのものを出力する記述をすることで回避できます。

"{{`{{.ID}}`}}"

text/template には記法の開始文字列と終了文字列をカスタマイズする方法があるため、ecspresso のコマンドライン引数で記法に使用する文字を切り替えることはできそうです。(要望があればissueでお願いします)

単純な値の展開だけでは記述しきれない処理をしたい

実際に利用するタスク定義は、数百行もの JSON になることがしばしばあります。多数のサイドカーをもつタスクでは複数のコンテナ定義に繰り返し同様の記述があるなど、変更の際のメンテナンス性が悪くなりがちです。

複数のタスク定義やコンテナ定義を共通化したいなど、ecspresso のテンプレートでは手に負えないような処理をしたい場合には、20日目 Jsonnetによる定義ファイル生成 を参照してください。

実際にテンプレートが評価された状態を確認したい

12日目のrenderコマンドの説明を参照してください。

ここで説明していないこと

Terraform の State ファイル(tfstate)に定義されている値を参照し、テンプレート内で展開する機能があります。19日目 Terraform tfstate連携を参照してください。


6日目はデプロイで問題が発生した場合にロールバックする方法について説明します。

https://zenn.dev/fujiwara/articles/ecspresso-20201206.md

Discussion