Edited at
AnsibleDay 15

You Don't Need common-roles in Ansible

More than 1 year has passed since last update.


話しておきたいこと

本記事は、 common-roles を用いたベストプラクティス構成を 非難している訳ではありません 。寧ろ、「 common-roles という共用したいロールを Playbook の外に出し管理する」という発想は素晴らしいものであると思っています。


前書き

構成管理ツールで Ansible を使ってる方は以下の記事を一度は見たことがあるのではないでしょうか?以下の記事を参考にすぐさまベストプラクティス構成を変更したことは記憶に新しいです。

Ansible オレオレベストプラクティス - Qiita

筆者は丁度 1 年ぐらい前に こちらの記事 を投稿しました。こちらの記事を見て分かると思うのですが、筆者は common-roles をベースとしたオレオレベストプラクティス構成で管理していました。しかし、現状は common-roles を用いない ( 必要としない ) ベストプラクティス構成となっております。 common-roles で供用したいロールを管理してもいいとは思いますが、筆者としては現状の common-roles を用いない ( 必要としない ) ロール管理の方がスマートで気に入ってます。ですので、今回はこちらの紹介をしたいと思います。


なぜ common-roles はもう必要ないのか?

共用ロールを common-roles で管理するのではなく、 Ansible Galaxy でファイル管理することで common-roles は必要なくります。

以下の Ansible Galaxy とは では Ansible Galaxy に知見がない方のために Ansible Galaxy — Ansible Documentation から筆者が重要だと思う項目のみ抜粋し意訳しています。「 ※ 補足 」については筆者が補足したい内容記述した箇所になります。


Ansible Galaxy とは

Ansible Galaxy は、ユーザーがロールをシェア出来る Web サイト Galaxy 及び、ロールのインストール・作成や管理するためのコマンドラインツールを指します。


Web サイト

Galaxy は、コミュニティが開発したロールを見つけ、ダウンロードし、共有するための無料のサイトです。 Galaxy からロールをダウンロードすることは、オートメーションプロジェクトを開始するのに最適です。

サイトを使用して、作成したロールを共有することも出来ます。 GitHub アカウントを使用してサイトで認証することで、ロールをインポートして、Ansible コミュニティで利用出来るようになります。 インポートされたロールは、Galaxy 検索索引で利用可能になりサイト上に表示され、ユーザーはそれらを見つけてダウンロードすることが出来ます。

About page を表示して詳細を確認して下さい。


コマンドラインツール

ansible-galaxy コマンドは Ansible にバンドルされています。 Galaxy から、または git ベースの SCM から直接ロールをインストールするために使用出来ます。 また、これを使用して、新しいロールを作成したり、ロールを削除したり、Galaxy Web サイトでタスクを実行することも出来ます。

コマンドラインツールは、デフォルトで、サーバーアドレス https://galaxy.ansible.com を使用して Galaxy Web サイト API と通信します。 Galaxy プロジェクト はオープンソースプロジェクトであるため、独自の内部 Galaxy サーバーを実行しており、既定のサーバーアドレスを上書きすることが出来ます。 これを行うには、 -server オプションを使用するか、 ansible.cfg ファイルに Galaxy サーバーの値を設定します。 secured.cfg の値を設定する方法については、 Galaxy Settings を参照して下さい。


ロールのインストール

ansible-galaxy コマンドを使用して、Galaxy Webサイトからロールをダウンロードします。

$ ansible-galaxy install username.role_name

※ 補足

ansible-galaxy は SCM ( git か hg ) をサポートしているため、 GitHub や Bitbucket といった git ホスティングサービスにアップロードしたロールもインストールすることが可能です。

※ プライベートリポジトリで管理されたロールもインストール可


ロールのインストールパス

デフォルトでは、 ANSIBLE_ROLES_PATH 環境変数で指定されたパスにロールがダウンロードされることに注意して下さい。 これは、一連のディレクトリ( すなわち、 /etc/ansible/roles:~/ansible/roles )に設定することが出来ます。この場合、最初の書き込み可能なパスが使用されます。 Ansible が最初にインストールされると、デフォルトでは /etc/ansible/roles になります。これには root 権限が必要です。

セッションで環境変数を設定し、 ansible.cfg ファイルで roles_path を定義するか、 -roles-path オプションを使用して、これを無効にすることが出来ます。 以下は、 -roles-path を使用して現在の作業ディレクトリにロールをインストールする例です。

$ ansible-galaxy install --roles-path . geerlingguy.apache

※ 参照して下さい

Configuration file


 すべての設定ファイルについて


バージョン

カンマと GitHub リリースタグの値を追加して、特定のバージョンのロールを Galaxy からインストール出来ます。例えば:

$ ansible-galaxy install geerlingguy.apache,v1.0.0

また、git リポジトリを直接指し、ブランチ名やコミットハッシュをバージョンとして指定することも出来ます。例えば、次のコマンドは特定のコミットをインストールします。

$ ansible-galaxy install git+https://github.com/geerlingguy/ansible-role-apache.git,0b7cd353c0250e87a26e0499e59e7fd265cc2f25

※ 補足

複数の共用ロールを一つ一つリポジトリで管理するため、バージョンを指定してインストールすることが可能です。


複数のロールをファイルからインストール

Asible 1.8 から、roles を requirements.yml ファイルに含めることで、複数のロールをインストールすることが可能です。 ファイルの形式はYAML で、ファイル拡張子は .yml または .yaml のいずれかでなければなりません。

requirements.yml に含まれるロールをインストールするには、次のコマンドを使用します:

$ ansible-galaxy install -r requirements.yml

この拡張子も重要です。 拡張子 .yml が指定されていない場合、対応していない ansible-galaxy CLI はファイルが古くなっているとみなし、現在は廃止された「基本」形式とみなします。

ファイル内の各ロールには、次の属性の 1 つ以上があります。

属性
意味

src
ロールのソース。 Galaxyからダウンロードする場合は、 username.role_name という形式を使用します。 それ以外の場合は、gitベースの SCM 内のリポジトリを指す URL を指定します。 以下の例を参照して下さい。 これは必須の属性です。

scm
SCM を指定します。 この執筆時点では、git または hg のみがサポートされています。 以下の例を参照して下さい。 デフォルトは git です。

version
ダウンロードするロールのバージョン。 リリースタグ値、コミットハッシュ、またはブランチ名を指定します。 デフォルトは master です。

name
ロールを特定の名前にダウンロードします。 GalaxyからダウンロードするときはデフォルトでGalaxyの名前になります。それ以外の場合はデフォルトでリポジトリの名前になります。

requirements.yml でロールを指定するためのガイドとして、次の例を使用して下さい:


requirements.yml

# from galaxy

- src: yatesr.timezone

# from GitHub
- src: https://github.com/bennojoy/nginx

# from GitHub, overriding the name and specifying a specific tag
- src: https://github.com/bennojoy/nginx
version: master
name: nginx_role

# from a webserver, where the role is packaged in a tar.gz
- src: https://some.webserver.example.com/files/master.tar.gz
name: http-role

# from Bitbucket
- src: git+http://bitbucket.org/willthames/git-ansible-galaxy
version: v1.4

# from Bitbucket, alternative syntax and caveats
- src: http://bitbucket.org/willthames/hg-ansible-galaxy
scm: hg

# from GitLab or other git-based scm
- src: git@gitlab.company.com:mygroup/ansible-base.git
scm: git
version: "0.1" # quoted, so YAML doesn't parse this as a floating-point value


※ 補足

requirements.yml は Playbook のロールを管理するためのファイルです。


ロールをパッケージで例えるならば、


  • Node.js でいうところの package.json

  • Ruby でいうところの Gemfile

  • PHP でいうところの composer.json

と言ったファイルと同じようなものです。

共用ロールを common-roles で管理するのではなく、 この requirements.yml ファイル管理するのがスマートです。


依存関係

ロールは他のロールに依存することもあり、依存関係を持つロールをインストールすると、それらの依存したロールが自動的にインストールされます。

meta/main.yml ファイルでロールの依存関係を指定するには、ロールのリストを指定します。 ロールのソースが Galaxy の場合は、単純に username.role_name の形式でロールを指定出来ます。 requirements.yml で使用されているより複雑な形式もサポートされているので、src、scm、バージョンおよび名前を指定することが出来ます。

Galaxyの依存関係は、次のように指定出来ます:


meta/main.yml

dependencies:

- geerlingguy.apache
- geerlingguy.ansible

複雑な形は、次のようにも使用することが出来ます:


meta/main.yml

dependencies:

- src: geerlingguy.ansible
- src: git+https://github.com/geerlingguy/ansible-role-composer.git
version: 775396299f2da1f519f0d8885022ca2d6ee80ee8
name: composer

ansible-galaxy によって依存関係が検出されると、それは自動的にroles_pathに各依存関係をインストールします。 プレイの実行中に依存関係がどのように処理されるかを理解するには、 Playbook Roles and Include Statements を参照して下さい。

※ この執筆時点では、Galaxy Web サイトでは、すべてのロールの依存関係が Galaxy に存在すると予想されています。したがって、依存関係は username.role_name 形式で指定する必要があります。 src の値が URL である依存関係を持つロールをインポートすると、インポートプロセスは失敗します。


ロールの作成

init コマンドを使用して、新しいロールの基本構造を初期化し、さまざまなディレクトリの作成に時間を節約し、ロールが必要とする main.yml ファイルを作成します。

$ ansible-galaxy init role_name

上記は、現在の作業ディレクトリに次のディレクトリ構造を作成します:

.

├── .travis.yml
├── README.md
├── defaults
│   └── main.yml
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── tasks
│   └── main.yml
├── templates
├── tests
│   ├── inventory
│   └── test.yml
└── vars
└── main.yml


Force

ロールの名前と一致するディレクトリが現在の作業ディレクトリにすでに存在する場合、 init コマンドはエラーになります。 エラーを無視するには、 -force オプションを使用します。 Force は上記のサブディレクトリとファイルを作成し、一致するものを置き換えます。


インストールされたロールの削除

roles_path からロールを削除するには、 remove を使用します。

$ ansible-galaxy remove username.role_name


何がスマートなのか

common-roles で共用ロールを管理する場合は以下のように、 common-roles とサービスごとの Playbook を一纏めにしてリポジトリで管理していました。


repository1

.

├── common-roles
│   ├── role1/ # 共用ロール1
│   ├── role2/ # 共用ロール2
│   └── role3/ # 共用ロール3
├── playbook1/ # service1 の Playbook
└── playbook2/ # service2 の Playbook

しかし、 requirements.yml で共用ロールを管理する場合は以下のように、 common-roles とサービスごとの Playbook を一つ一つリポジトリで管理することが可能です。


repository1

role1/



repository2

role2/



repository3

role3/



repository4

playbook1/



repository5

playbook2/


こうすることで、ロールと Playbook それぞれのバージョンを指定して実行できたり、管理が楽になります。

更に、以下のようにサービスごとに Playbook がどの共用ロールを使用しているかが requirements.yml ファイルを見ることで把握出来ます。


playbook1/requirements.yml

- src: kotarella1110.role1

- src: https://github.com/kotarella1110/role2
version: v1.3


playbook2/requirements.yml

- src: kotarella1110.role1

- src: kotarella1110.role3


Playbook の Best Operation


common-roles 内の共用ロールを Galaxy にアップロード

common-roles 内の共用ロールは汎用的に作られていると思うので、プライベートな情報を保持しているというロール少ないと思います。

公開出来る共用ロールは Galaxy にアップロードしてしまいましょう。フィードバックがあるかもしれません。


Galaxy へのアップロード方法を知りたい方は roleを作成してAnsible Galaxyに登録するワークフロー - Qiita を参照して下さい。非常に分かりやすく記載されています。

中には公開出来ない共用ロールがあると思います。そのようなロールはプライベートリポジトリで管理します。

何回も言うようですがプライベートリポジトリも requirements.yml で管理出来ます。

筆者は基本的に共用ロールは Galaxy にアップロードした、もしくはされたロールを利用し、サービスごとの Playbook はサービス独自の個別設定等といった公開したくない情報が入っているため、プライベートリポジトリで管理しています。


偉人が作成した Galaxy のロールを極力採用する

共用ロールはどんなサービスごとの Playbook でも使える、汎用的なロールであるべきです。

しかし、供用ロールを本気で作ろうとするとプラットフォームを考慮したりするため一苦労です。

そこで偉人が作成した Galaxy ロールを採用しましょう。ほとんどの場合が、自分の作成したいロールは偉人が作成したロールで完結してしまうはずです。

Galaxy の Browse Roles から様々なロールを探すことが可能です。ダウンロード数や GitHub のスター数、サポートしているプラットフォームを確認して、目的に即したロールをインストールしましょう。

筆者は実際にロールを採用する前に必ず、偉人が作成したロールのコードリーディングを行うようにしています。

いくら、偉人が作成したロールとはいえ間違えがある可能性も十分にあります。間違えを発見したらプルリクを出して貢献しましょう。

偉人の Galaxy ロールだけでは目的に即さない場合もあると思います。

そのような時は、 Galaxy のロールを改変して利用するのが手っ取り早いです。

※ Galaxy のロールを改変して利用する際はライセンスに注意して下さい。


Galaxy のロールを改変する際の管理

Galaxy のロールを改変し目的に即したロールを作成する際に避けたい事態が存在します。

それは Galaxy のロール ( 本家 ) に修正が加わった際に、その修正内容を反映せず、放置してしまうという事態です。

しかし、以下のように Git を上手く利用し本家リポジトリに追従することでこの問題を回避出来ます。

GitHubでFork/cloneしたリポジトリを本家リポジトリに追従する - Qiita

本家のリポジトリに追従しながら変更を加えることが可能になり、効率的なロールの管理が出来ます。

Galaxy のロールである geerlingguy.apache に追従してみましょう。 GitHub リポジトリは geerlingguy/ansible-role-apache です。


Galaxy のロールを clone

$ git clone git@github.com:geerlingguy/ansible-role-apache.git geerlingguy.apache

cd geerlingguy.apache/
$ git remote -v
origin git@github.com:geerlingguy/ansible-role-apache.git (fetch)
origin git@github.com:geerlingguy/ansible-role-apache.git (push)
$ git branch -a
_ master
remotes/origin/HEAD -> origin/master
remotes/origin/master


リモートリポジトリを追加

オリジナルのリポジトリを upstream という名前で設定。

$ git remote add upstream git@github.com:geerlingguy/ansible-role-apache.git

$ git remote -v
origin git@github.com:geerlingguy/ansible-role-apache.git (fetch)
origin git@github.com:geerlingguy/ansible-role-apache.git (push)
upstream git@github.com:geerlingguy/ansible-role-apache.git (fetch)
upstream git@github.com:geerlingguy/ansible-role-apache.git (push)


本家リポジトリの変更を取り出すために fetch

$ git fetch upstream

From github.com:geerlingguy/ansible-role-apache
_ [new branch] master -> upstream/master
$ git branch -a
_ master
remotes/origin/HEAD -> origin/master
remotes/origin/master
remotes/upstream/master


反映したいリポジトリにチェックアウトし merge

$ git checkout master

$ git merge upstream/master


依存関係を上手く利用する


供用ロールに依存するロールもインストールしたい

例えば、以下のように geerlingguy.jenkins ロールは geerlingguy.java ロールに依存してます。


geerlingguy.jenkins/meta/main.yml

---

dependencies:
- geerlingguy.java
...

この時、 geerlingguy.jenkins をインストールすると以下のように geerlingguy.java もインストールされます。

$ ansible-galaxy install -p . geerlingguy.jenkins

- downloading role 'jenkins', owned by geerlingguy
- downloading role from https://github.com/geerlingguy/ansible-role-jenkins/archive/2.6.0.tar.gz
- extracting geerlingguy.jenkins to ./geerlingguy.jenkins
- geerlingguy.jenkins was installed successfully
- adding dependency: geerlingguy.java
- downloading role 'java', owned by geerlingguy
- downloading role from https://github.com/geerlingguy/ansible-role-java/archive/1.7.1.tar.gz
- extracting geerlingguy.java to ./geerlingguy.java
- geerlingguy.java was installed successfully

$ ls

geerlingguy.java/ geerlingguy.jenkins/


タスクの notify セクションに供用ロールの handlers タスクを定義したい

供用ロールである geerlingguy.nginx ロールのタスクを実行後、 Playbook 独自の nginx ロールのタスクを実行したいというケースはあると思います。


requirement.yml

- src: geerlingguy.nginx



playbook

.

├── hosts/
├── group_vars/
├── host_vars/
├── web.yml
├── roles
│   └── nginx/
└── requirement.yml

以下のように定義すると、供用ロールである geerlingguy.nginx ロールと nginx ロールはお互いに関係を持たないため、 nginx ロールのタスクの notify セクションに geerlingguy.nginx/handlers/main.yml の handlers タスク ( restart nginx など ) を定義しても実行されません。そのため、 nginx/handlers/main.ymlgeerlingguy.nginx/handlers/main.yml と重複する handlers タスクを定義する必要があります。これはスマートではないです。


web.yml

- hosts: web

sudo: yes
roles:
- geerlingguy.nginx
- nginx

このような時は、以下のように依存関係を持つことで、 nginx ロールは geerlingguy.nginx ロールの handlers を実行することが出来るようになります。


roles/nginx/meta/main.yml

dependencies:

- geerlingguy.nginx


web.yml

- hosts: web

sudo: yes
roles:
- nginx


requirements.yml 内のロールをアップデート

requirements.yml 内のロールをアップデート ( 上書き ) したい場合は -force オプションを使用します。

ロールの名前と一致するディレクトリがインストール先ディレクトリに既にに存在する場合、 install コマンドはエラーになります。

$ ansible-galaxy install -f -r requirements.yml


参考文献