PackerのAnsibleProvisionerでインベントリ毎のgroup_varsを使い分ける
PackerのAnsibleProvisionerでインベントリ毎のgroup_varsを使い分ける:
この記事は、エーピーコミュニケーションズ Advent Calendar 2018 の22日目のエントリです。
今回もAnsible絡みですが、Packerを使ってAWS EC2にAMIをデプロイします。
PackerにはProvisionerというVM起動後にインストール作業や設定変更ができる機能があり、
その中にAnsible Provisionerがあるのでそちらを使います。
PackerのProvisionerにはAnsibleの他にもShellやPowerShell, Chef, Puppetなどなど各種あるのでお好みのツールを使えると思います。
ちなみにもう一つAnsible Local Provisionerというものがありますが、そちらは試していません。
Packerは基本的に1台のマシンイメージ(AMI)を作成するツールですが、
Ansibleは複数のマシンをホスト名やグループ名によってインストールするパッケージなどの処理を変えながら構築していくことを多いと思われます。
こういった使い方をPackerで実現するため、所属するグループをサーバの役割毎に動的に変更させることによって複数種類のAMIを作成させます。
また、Packerではインベントリを使用せずにPlaybookのみで動作させることができます。
クラウドでは基本的にIPやホスト名が動的に割り当てられるため、あらかじめインベントリを作成しておくのが困難なので、作成する必要がないのは楽ですね。
インベントリを使用しなくてもPlaybook側の
Ansible BestpracticeにあるAlternative Directory Layoutの例のように
「商用とステージングでPlaybookとグループは共通のものを使いたいけど、IPアドレスやURLなどの変数には別々の値を使いたい」という場合には
複数のインベントリファイル・ディレクトリに分けて使い分ける、という使い方をしているケースも多く、
その場合にはインベントリの
インベントリのディレクトリ構成例(Best Practicesから抜粋)
Packerでインベントリの
意外にもあまり情報が見つからなかったのでPackerの公式などを調べて動かした結果を書きます。
packerコマンドを実行するディレクトリからの相対的なファイル構成は以下のようにしました。
そして
ポイントとしては、インベントリファイルは作成しないで、
そしてPackerの設定ファイルは以下のように書きました。
ポイントとしては
その上でgroupsにグループ名を指定する
ということです。
それでは実際に動作確認してみましょう。
Playbookは以下のようにしています。
各種ファイルに書いた変数はこちら
Packerでは
実行結果は以下のようになりました。(Packerのメタな部分は適度にボカしてます)
想定した通りになってますね!
ちなみにinventory_directoryの説明にもあるように、
inventory_directoryに指定したディレクトリに一時ファイルとしてインベントリファイルを作成します。
一時ファイルなので完了/失敗時に削除されるのですが、
その場合、どういう挙動なのかよくわかってませんが、次回実行時に残ったインベントリファイルを読み込んでデプロイにコケる、というケースがありました。
挙動がおかしい場合はインベントリディレクトリを調査して、インベントリファイルが残ってたら削除するとうまくいきました。
他にもいい方法があればコメントください。
はじめに
この記事は、エーピーコミュニケーションズ Advent Calendar 2018 の22日目のエントリです。今回もAnsible絡みですが、Packerを使ってAWS EC2にAMIをデプロイします。
PackerにはProvisionerというVM起動後にインストール作業や設定変更ができる機能があり、
その中にAnsible Provisionerがあるのでそちらを使います。
PackerのProvisionerにはAnsibleの他にもShellやPowerShell, Chef, Puppetなどなど各種あるのでお好みのツールを使えると思います。
ちなみにもう一つAnsible Local Provisionerというものがありますが、そちらは試していません。
やりたいこと
Packerは基本的に1台のマシンイメージ(AMI)を作成するツールですが、Ansibleは複数のマシンをホスト名やグループ名によってインストールするパッケージなどの処理を変えながら構築していくことを多いと思われます。
こういった使い方をPackerで実現するため、所属するグループをサーバの役割毎に動的に変更させることによって複数種類のAMIを作成させます。
また、Packerではインベントリを使用せずにPlaybookのみで動作させることができます。
クラウドでは基本的にIPやホスト名が動的に割り当てられるため、あらかじめインベントリを作成しておくのが困難なので、作成する必要がないのは楽ですね。
インベントリを使用しなくてもPlaybook側の
group_vars
を使用すれば上記の挙動は実現可能ですが、Ansible BestpracticeにあるAlternative Directory Layoutの例のように
「商用とステージングでPlaybookとグループは共通のものを使いたいけど、IPアドレスやURLなどの変数には別々の値を使いたい」という場合には
複数のインベントリファイル・ディレクトリに分けて使い分ける、という使い方をしているケースも多く、
その場合にはインベントリの
host_vars
, group_vars
を使い分ける必要があります。インベントリのディレクトリ構成例(Best Practicesから抜粋)
inventories/ production/ hosts # inventory file for production servers 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 staging/ hosts # inventory file for staging environment group_vars/ group1.yml # here we assign variables to particular groups group2.yml host_vars/ stagehost1.yml # here we assign variables to particular systems stagehost2.yml
Packerでインベントリの
group_vars
を使う良い方法が調べていたのですが、意外にもあまり情報が見つからなかったのでPackerの公式などを調べて動かした結果を書きます。
書き方
ファイル構成
packerコマンドを実行するディレクトリからの相対的なファイル構成は以下のようにしました。ファイル構成
. ├── ansible │ ├── group_vars │ │ ├── all.yml │ │ ├── db.yml │ │ └── web.yml │ ├── inventory │ │ ├── production │ │ │ └── group_vars │ │ │ └── all.yml │ │ └── staging │ │ └── group_vars │ │ └── all.yml │ └── play.yml └── packer.json
packer.json
がpackerコマンドで引数となる設定ファイルで、今回は実行ディレクトリ直下においています。そして
ansible/inventory/production
およびansible/inventory/staging
がインベントリに当たるディレクトリですが、ポイントとしては、インベントリファイルは作成しないで、
group_vars
のみ(必要ならhost_vars
も)を置いている点です。そしてPackerの設定ファイルは以下のように書きました。
packer.json
{ "variables": { "environment": "staging", "instance_type": "t2.micro", "source_ami": "ami-0a2de1c3b415889d2", "role": "" }, "builders": [ { "type": "amazon-ebs", "ami_name": "packer_ami_{{timestamp}}", "instance_type": "{{user `instance_type`}}", "source_ami": "{{user `source_ami`}}", "ssh_username": "ec2-user", "tags": [ { "Name": "packer_ami" } ] } ], "provisioners": [ { "playbook_file": "ansible/play.yml", "inventory_directory": "ansible/inventory/{{user `environment`}}", "type": "ansible", "user": "ec2-user", "groups": ["{{user `role`}}"], "extra_arguments": [] } ] }
provisioners
のディレクティブでinventory_directoryを指定して、その上でgroupsにグループ名を指定する
ということです。
それでは実際に動作確認してみましょう。
Playbookは以下のようにしています。
ansible/play.yml
- hosts: all become: true tasks: - name: インベントリのgroup_vars/all.ymlの確認 debug: msg: "my environment is {{ env }}" - name: プレイブックのgroup_vars/all.ymlの確認 yum: name: "{{ common_package }}" - name: プレイブックのgroup毎のgroup_varsの確認 yum: name: "{{ item }}" loop: "{{ dist_package }}" - hosts: web tasks: - name: webグループの挙動確認 debug: msg: "I am Web!!!" - hosts: db tasks: - name: dbグループの挙動確認 debug: msg: "I am db!!!"
:::::::::::::: ansible/group_vars/all.yml :::::::::::::: common_package: git :::::::::::::: ansible/group_vars/db.yml :::::::::::::: dist_package: - mysql - mariadb-server :::::::::::::: ansible/group_vars/web.yml :::::::::::::: dist_package: - httpd - php :::::::::::::: ansible/inventory/production/group_vars/all.yml :::::::::::::: env: production :::::::::::::: ansible/inventory/staging/group_vars/all.yml :::::::::::::: env: staging
-var arg=var
という形式でvariables
で指定した変数を上書きできます。(--var
ではなくハイフン1つなので注意)実行結果は以下のようになりました。(Packerのメタな部分は適度にボカしてます)
実行結果
$ packer build -var environment=production -var role=web packer.json amazon-ebs output will be in this color. ==> amazon-ebs: Prevalidating AMI Name: packer_ami_1545451854 amazon-ebs: Found Image ID: ami-0a2de1c3b415889d2 ==> amazon-ebs: Creating temporary keypair: packer_*************** ==> amazon-ebs: Creating temporary security group for this instance: packer_*************** ==> amazon-ebs: Authorizing access to port 22 from 0.0.0.0/0 in the temporary security group... ==> amazon-ebs: Launching a source AWS instance... ==> amazon-ebs: Adding tags to source instance amazon-ebs: Adding tag: "Name": "Packer Builder" amazon-ebs: Instance ID: i-*************** ==> amazon-ebs: Waiting for instance (i-***************) to become ready... ==> amazon-ebs: Using ssh communicator to connect: *************** ==> amazon-ebs: Waiting for SSH to become available... ==> amazon-ebs: Connected to SSH! ==> amazon-ebs: Provisioning with Ansible... ==> amazon-ebs: Executing Ansible: ansible-playbook --extra-vars packer_build_name=amazon-ebs packer_builder_type=amazon-ebs -i ansible/inventory/production /home/hogehoge/code/packer-ansible/ansible/play.yml -e ansible_ssh_private_key_file=/tmp/ansible-key657870806 amazon-ebs: amazon-ebs: PLAY [all] ********************************************************************* amazon-ebs: amazon-ebs: TASK [Gathering Facts] ********************************************************* amazon-ebs: ok: [default] amazon-ebs: amazon-ebs: TASK [インベントリのgroup_vars/all.ymlの確認] ******************************************** amazon-ebs: ok: [default] => { amazon-ebs: "msg": "my environment is production" amazon-ebs: } amazon-ebs: amazon-ebs: TASK [プレイブックのgroup_vars/all.ymlの確認] ******************************************** amazon-ebs: changed: [default] amazon-ebs: amazon-ebs: TASK [プレイブックのgroup毎のgroup_varsの確認] ********************************************* amazon-ebs: changed: [default] => (item=httpd) amazon-ebs: changed: [default] => (item=php) amazon-ebs: amazon-ebs: PLAY [web] ********************************************************************* amazon-ebs: amazon-ebs: TASK [Gathering Facts] ********************************************************* amazon-ebs: ok: [default] amazon-ebs: amazon-ebs: TASK [webグループの挙動確認] ************************************************************ amazon-ebs: ok: [default] => { amazon-ebs: "msg": "I am Web!!!" amazon-ebs: } amazon-ebs: [WARNING]: Could not match supplied host pattern, ignoring: db amazon-ebs: amazon-ebs: PLAY [db] ********************************************************************** amazon-ebs: skipping: no hosts matched amazon-ebs: amazon-ebs: PLAY RECAP ********************************************************************* amazon-ebs: default : ok=6 changed=2 unreachable=0 failed=0 amazon-ebs: ==> amazon-ebs: Stopping the source instance... amazon-ebs: Stopping instance, attempt 1 ==> amazon-ebs: Waiting for the instance to stop... ==> amazon-ebs: Creating unencrypted AMI packer_ami_1545451854 from instance i-*************** amazon-ebs: AMI: ami-*************** ==> amazon-ebs: Waiting for AMI to become ready... ==> amazon-ebs: Adding tags to AMI (ami-***************)... ==> amazon-ebs: Tagging snapshot: snap-*************** ==> amazon-ebs: Creating AMI tags amazon-ebs: Adding tag: "Name": "packer_ami" ==> amazon-ebs: Creating snapshot tags ==> amazon-ebs: Terminating the source AWS instance... ==> amazon-ebs: Cleaning up any extra volumes... ==> amazon-ebs: No volumes to clean up, skipping ==> amazon-ebs: Deleting temporary security group... ==> amazon-ebs: Deleting temporary keypair... Build 'amazon-ebs' finished. ==> Builds finished. The artifacts of successful builds are: --> amazon-ebs: AMIs were created: ap-northeast-1: ami-***************
ちなみにinventory_directoryの説明にもあるように、
inventory_directoryに指定したディレクトリに一時ファイルとしてインベントリファイルを作成します。
一時ファイルなので完了/失敗時に削除されるのですが、
Ctrl+C
を連打したりすると削除処理までキャンセルしてしまう場合がありました。その場合、どういう挙動なのかよくわかってませんが、次回実行時に残ったインベントリファイルを読み込んでデプロイにコケる、というケースがありました。
挙動がおかしい場合はインベントリディレクトリを調査して、インベントリファイルが残ってたら削除するとうまくいきました。
他にもいい方法があればコメントください。
コメント
コメントを投稿