はじめに
今担当しているシステムでは、AWS Identity Center
を使い、キーペアを持たない運用を行っておりますが、Ansible
をEC2インスタンスに実行する場合、Ansible
の仕組み上、SSH
を行う必要があることから、Ansible
を使うためにはキーペアを持たなくてはならないと思っていました。
しかし、AWS Systems Manager Run Command
を使用すれば、キーペアを使わずに対象のEC2インスタンスにAnsible
を実行できるため、今回はAWS Systems Manager Run Command
を使ってキーペアなしでAnsible
を実行する際の最適なディレクトリレイアウトについて検討してみようと思います。
AWS Systems Manager Run CommandでのAnsible実行
以前の記事でAWS Systems Manager
からのAnsible
実行を試しましたが、Systems Manager Run Command
でAnsible
を実行する場合、Run Command
で指定するターゲットで対象を指定することから、インベントリファイルによる制御は行えず、ターゲット全てlocalhost
で実行されます。
そのため、ベストプラクティス構成のPlaybook
を実行しようとしても、ホストはlocalhost
一択となるため、group_vars
やhosts_vars
による変数切り替えができず、単純に実行するPlaybook
を切り替えるだけではサーバ種別ごとに変数を分けることが難しいです。
そのような特徴を持つRun Command
によるAnsible
を実行する上で、なるべくベストプラクティスの構成を変えずに、あまり修正すること無くRun Command
によるPlaybook実行も、通常のインベントリファイル指定でのPlaybook実行もできるようにしてみたいと思います。
以下、以前紹介した記事。
Ansibleのベストプラクティス構成
Ansible
の公式でベストプラクティスのディレクトリレイアウトとして紹介されている構成は以下となります。
.
├── production # inventory file for production servers staging # inventory file for staging environment
├── group_vars/
│ └── group1.yml # here we assign variables to particular groups group2.yml
├── host_vars/
│ └── hostname1.yml # here we assign variables to particular systems hostname2.yml
├── library/ # if any custom modules, put them here (optional) module_utils/ # if any custom module_utils to support modules, put them here (optional) filter_plugins/ # if any custom filter plugins, put them here (optional)
├── site.yml # master playbook webservers.yml # playbook for webserver tier dbservers.yml # playbook for dbserver tier
└── roles/
├── common/ # this hierarchy represents a “role”
│ ├── tasks/ #
│ │ └── main.yml # <– tasks file can include smaller files if warranted
│ ├── handlers/ #
│ │ └── main.yml # <– handlers file
│ ├── templates/ # <– files for use with the template resource
│ │ └── ntp.conf.j2 # <——- templates end in .j2
│ ├── files/ #
│ │ └── bar.txt # <– files for use with the copy resource foo.sh # <– script files for use with the script resource
│ ├── vars/ #
│ │ └── main.yml # <– variables associated with this role
│ ├── defaults/ #
│ │ └── main.yml # <– default lower priority variables for this role
│ ├── meta/ #
│ │ └── main.yml # <– role dependencies
│ └── library/ # roles can also include custom modules module_utils/ # roles can also include custom module_utils lookup_plugins/ # or other types of plugins, like lookup in this case
└── webtier/ # same kind of structure as “common” was above, done for the webtier role monitoring/ # “” fooapp/ # “”
上記例で言うと、普通にPlaybook
を実行する場合には、production
というインベントリファイルを指定してsite.yml
を実行することで、インベントリファイルに記載されているグループ名(group1
)とホスト名(hostname1
)に該当する変数がgroup_vars
、host_vars
から呼び出されsite.yml
に記載されている実行ロール名(common
やwebtier
)が実行される流れとなります。
また、site.yml
は各サーバごとの処理を記載したPlaybook
をimport_playbook
で読み込む程度の処理しか行わないというのがベストプラクティスとなるため、実際に実行するロールを指定するPlaybook
は以下でいうとwebservers.yml
やdbservers.yml
となります。
---
# file: site.yml
- import_playbook: webservers.yml
- import_playbook: dbservers.yml
私が考えたAWS Systems Manager Run Commandで実行する場合のベストプラクティス構成
詳細は後述しますが、以下は俗に言う「俺が考えた最強の○○」
.
├── group_vars/
│ └── group1.yml
├── ssm_webservers.yml
├── ssm_dbservers.yml
└── roles/
├── common/
│ ├── tasks/
│ │ └── main.yml
│ ├── handlers/
│ │ └── main.yml
│ ├── templates/
│ │ └── ntp.conf.j2
│ ├── files/
│ │ └── bar.txt
│ ├── vars/
│ │ └── main.yml
│ ├── defaults/
│ │ └── main.yml
│ ├── meta/
│ │ └── main.yml
│ └── library/
└── webtier/
Run Command
での実行だけではなく、普通にPlaybook
を実行する場合でもあまり構成を変えずに実行したかったため、基本的なディレクトリレイアウトはベストプラクティスの構成とほぼ同じです。
インベントリファイルはRun Command
では使えないため除外、site.yml
もRun Command
で実行する場合はインポートする意味がないので除外、host_vars
もホスト単位での変数指定はRun Command
では難しいため、こちらも除外。
group_vars
はそのままでは全てのホストを示すall.yml
しか読み込んでくれないため、host_vars
と同じようにあまり意味がないのですが、Playbook
にパス指定して読み込ませるようにすることで、既存のgroup_vars
変数ファイルを使い回せることが分かったので、そのまま使用します。
Run Commandで実行する場合に用意するファイル
上記のディレクトリレイアウトでRun Command
で実行する場合に準備するファイルについて以下で見ていきます。
site.yml
がない代わりにsite.yml
から読み込まれるサーバ種別ごとのPlaybook
をRun Command
用に準備します。
Playbook
内のhosts
の指定は、localhost
しか指定できないのでlocalhost
は固定として、vars_files
でgroup_vars
に存在するグループ用変数をAnsible
ディレクトリからの相対パス指定で読み込みます。
こうすることで、group_vars
の変数ファイルは既存のまま使用することができるのでRun Command
用に準備するファイルはPlaybook
ファイルとなるssm_webserver.yml
やssm_dbserver.yml
のみで済むことになります。
---
- become: true
hosts: localhost
vars_files:
- group_vars/group1.yml
roles:
- common
Systems Manager Run CommandによるAnsibleの実行
Systems Manager Run Command
で実行する場合は、ターゲットをRun Command
の画面から指定して、Playbook File
でssm_webserver.yml
やssm_dbserver.yml
を指定すれば動きます。
ターゲットは複数指定できても、ターゲットに対して実行されるPlaybook
ファイルをターゲットごとに分けることはできないので、もし実行するPlaybook
ファイルを分けたい場合は、別々に実行しましょう。
注意点
Run Command
によるAnsible
実行は、実行するたびにAnsible
のPlaybook
などを毎回ダウンロードする仕組みとなります。
そのため、roles
のfiles
などにインストール用パッケージを置いたりするようなことは行わず、S3等からダウンロードするようにした上で、roles
実行する場合も条件式等を使い、毎回インストール用パッケージ等がダウンロードされないようにするのが良いかと思います。
- インストール用パッケージ等のサイズが大きいファイルはAnsibleのディレクトリには置かずに別のストレージに置く
- Playbookの条件式や実行rolesで制御してサイズの大きいファイルがダウンロードされないようにする
おわりに
Playbook
ファイルでvars_files
で変数ファイルを指定することで既存のAnsible
にあまり手を入れること無く使い回すことができました。
1台毎に別々のPlaybook
ファイルを準備すれば、もちろんhost_vars
でのホスト用変数の呼び出しもできますし、多分Playbook
ファイル内で条件式等書いて1台に絞り込むような処理が書ければ、既存のAnsibleはそのままで操作感変わらずに実行することもできるかと思います。
Ansible
を実行するためだけにキーペア運用を行っている方は、今回の記事を見てキーペアを消してみてはいかがでしょうか。