こんにちは。晩酌に(第3の)ビールを辞めてウィスキーにしたら体重が減り始めた照井@札幌です。やっぱりビールはよくないですね。おつまみが欲しくなりやすい気もしますし。アイラ系もたまに飲むと美味しいんですが、日常的に飲むにはグレンリベットとか正統派?のシングルモルトが美味しいですね。値段もお手頃ですし。
さて、サーバーワークスでは、運用業務の効率化と高品質化のためにEC2 Systems Managerの利用を進めております(下記参照)
ですが、同サービスの実際に実行する内容を定義するDocumentがある種かつてのCloudFormationを思わせる独特なJSONによる定義となっており、なかなか扱いづらい部分があります。そこで、これを解決するための「rezept」というツールを作り、RubyGemsおよびGitHubで公開しました。
どんなツール?
コードなど
名前の由来
Systems Managerは、Inventoryを集める仕組みがあったり、Agentによる実行だったり、どことなくChefっぽさがあります。Chefでは実行内容を定義したものをCookbookやRecipe(料理のレシピ本のこと)と呼び、AnsibleだとPlaybook(アメリカンフットボールの作戦をまとめた本のこと)と呼んだりします。
そんな中で、SSM Documentがどういった位置づけになるかというと、構築の自動化よりは運用の自動化寄りで、パッチ当てなどを行う使い方がメインになることを考えると「処方箋」っぽいなと思い、医学用語といえばドイツ語で処方箋を意味する「rezept」(日本語っぽく読むとレセプト)としました。
使い方
インストール
RubyGemsなのでこれだけです(要Ruby環境)
$ gem install rezept
各コマンドの使い方
基本のコマンドとオプションを解説します。その他のコマンドやオプションもありますので、詳しくはREADMEをご確認ください。
既存設定のエクスポート
$ rezept export --write
まず、既に利用している場合は既存の設定を取り込む必要があります。その場合、上記コマンドを実行します。
--write
を付けることでファイル(標準では Docfile
)に書き込みます。外すとコンソールに出力するのみとなります。
また、標準ではAmazonが管理しているDocument(全ユーザ共通のもの)はユーザが触れないため対象外としています。例外的に確認用などで全て出力したい場合は --amazon-docs
を付けます。
設定の反映
$ rezept apply
記述した設定を反映するには上記コマンドを実行します。 すると、下記のようなCRUD(Rはないけど)の有無とUpdateの場合は差分が表示され更新が行われます。
当然ながら? --dry-run
を付けることでCRUDの有無と差分のみ表示し、実際の更新は行わないようにできます。
実際の書き方
基本的な書き方
実際のファイルは以下のようなものになります。
Command "My-RunShellScript" do
account_ids []
content do
__dsl do
schemaVersion "2.0"
description "Run a shell script."
mainSteps do |*|
action "aws:runShellScript"
name "runShellScript"
inputs do
runCommand ["echo 1"]
end
end
end
end
end
まず、Command "My-RunShellScript"
の Command
部分で、それがCommand(既存インスタンス上でのコマンド実行)なのかAutomation(AWSリソースなどを操作するために専用のIAM Roleを持ったインスタンスを新規で立ち上げて実行)を指定します。 "My-RunShellScript"
がDocument名にあたります。
account_ids
は共有するAWSアカウントのIDを列挙します。誰でも使えるPublicなDocumentとする場合は ["All"]
と記述します(このあたりはAPI仕様に準拠)
content
以下が実際にはJSONとして保存されるDocumentの実行内容の定義です。詳しい書き方はAWSのドキュメントをご確認ください。
このように全てが一つのJSONで定義できるわけではなく、共有の設定はAPIが分かれていたりする点も専用のDSLを作るべきと判断した理由の一つです。
便利な独自構文
プログラマブルなRuby DSLの特徴を活かし、実際のDocument記述でペインポイントとなるような部分に一部対応しています。
コマンド部分をスクリプトとして記述する
通常のJSONなSSM Documentでは、コマンド等の記述は複数行となる場合に一行ずつ配列での記述が必要となります。それを普通にスクリプトとして書けるためのメソッドを用意しています。script
でヒアドキュメントを使ってDSL内にインラインで記述、 script_file
で外部のファイル読み込みを行うことができます。
- __script
Command "My-RunShellScript" do
account_ids []
content do
__dsl do
schemaVersion "2.0"
description "Run a shell script."
mainSteps do |*|
action "aws:runShellScript"
name "runShellScript"
inputs do
runCommand __script(<<-'EOS')
#! /bin/bash
echo 1
echo 2
echo 3
EOS
end
end
end
end
end
- __script_file
Command "My-RunShellScript" do
account_ids []
content do
__dsl do
schemaVersion "2.0"
description "Run a shell script."
mainSteps do |*|
action "aws:runShellScript"
name "runShellScript"
inputs do
runCommand __script_file("script.sh")
end
end
end
end
end
テンプレート
テンプレートを定義して記述を再利用することができます。引数で可変部分を表現することもできます。
template "runShellScriptTemplate" do
content do
__dsl do
schemaVersion "2.0"
description "Run a shell script"
mainSteps do |*|
action "aws:runShellScript"
name "runShellScript"
inputs do
runCommand __script(context.commands)
end
end
end
end
end
Command "My-RunShellScript" do
account_ids []
include_template "runShellScriptTemplate", commands: "echo 1"
end
Command "My-RunShellScript-2" do
account_ids []
include_template "runShellScriptTemplate", commands: "echo 2"
end
まとめと余談
いかがでしょうか。複雑なSSM Documentの記述と管理がこれで楽になると良いなと思います。サーバーワークスでは、Systems Managerを利用した運用の効率化と高品質化を継続して行っていく予定ですので、本ツールもさらにブラッシュアップされていくことと思います。直近では、実行についてもなんらかの形でサポートすることを検討中です。
私見ですが、JSONは手書きするのがとても大変です。最近では、AWSが各種設定をJSONで表現するのはそれをユーザが良い感じに自動生成することを想定しているのではないかと思うようになりました。
また、このアイデアはお気づきの方もいらっしゃるかと思いますが、Codenize.toolに強くインスパイアされています。関連するライブラリでは同じものを使わせてもらっていたりします。偉大な先人こと @sgwr_dts さんに感謝です。そして、こういう活動をしてフィードバックなどを送っていたらKumogata関連のコミット権を貰いましたw最後になりましたが、ありがとうございます。