Ansible Galaxyを使って楽々ロールの再利用

Ansibleには作成したロールをシェアするためのハブとしてAnsible Galaxyが用意されています。Ansible GalaxyによってChefのCommunity Cookbookのように他人が作成したAnsibleのロールを簡単に再利用することができます(もちろん自分で作成したロールを公開することも可能です)。

今回はこのAnsible Galaxyの仕組みを少し試してみたいと思います。Ansibleのバージョンは1.9.2を使います。

なおAnsibleの導入に関しては省略しますので、未導入の方はAnsibleとVagrantで開発環境を構築するなどを参考に導入してください。

準備

例によってVagrantを利用して試してみましょう。

以下のようにディレクトリを作り、その中で作業していきます。MacもしくはLinuxなどで試してみてください。

$ mkdir try-ansible-galaxy
$ cd try-ansible-galaxy

ディレクトリ内に以下の内容でVagrantfileを書きAnsibleのベストプラクティスに沿った形でインベントリファイルとトップレベルのプレイブックを作成してください。

Vagrantfile

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "hansode/centos-6.5-x86_64"

  config.vm.network "private_network", ip: "192.168.33.10"
end

provisioning/development

[nodejsservers]
192.168.33.10

provisioning/site.yml

---
- include: nodejsservers.yml

provisioning/nodejsservers.yml

---
- hosts: nodejsservers
  sudo: yes
  roles:

rolesは後ほど追加していきますので今は空のままにしておきます。

仮想マシンの起動

ここまでできたら

$ vagrant up

で仮想マシンを起動します。

nodejsservers.ymlが中途半端ですが、今回はVagrantのプロビジョニング機能は使わず、後ほどansible-playbookコマンドでプロビジョニングしますので気にせず起動してください。

ロールを探してインストールする

今回は試しにNode.jsをAnsible Galaxyから入れてみようと思います。

ロールを探す

まずはNode.jsをインストールするためのロールを探す必要があります。

ロールはAnsible GalaxyのサイトのBrowse Rolesのページで探すことができます。


Browse Roles - Ansible Galaxy

カテゴリおよびロール名での絞り込みを行うことができ、ロール名、作者名、スコア、作成日などでのソートが可能です。

とりあえずの探し方としてはキーワードを入れてスコアで降順ソートするのがよさそうです。

ただしレーティング自体あまり使われていないようで、スコアが付いていないロールも多いです。そのため、このスコアも今のところはないよりマシ程度のものでしかありません。

ロールの互換性をチェックする

今回は node で検索してスコアで降順ソートすると一番に表示されるJasonGiedymin.nodejsに目星をつけました。

目星をつけたらまずはJasonGiedymin.nodejsのページにあるSupported PlatformsMinimum Ansible Versionといった項目をチェックします。


サポートされるプラットフォームなど

それを見るとこのロールはDebian系とRedhat系の両方に対応したロールで、Ansible 1.3以上ならば動作するようです。今回使うのはAnsible1.8.2でセットアップ対象の環境はCentOSなので問題ありませんね。

せっかくロールを見つけてもプラットフォームがサポート対象外で使えないことがままあります。ロールの検索フォームにはサポートするプラットフォームで絞り込む機能が欲しいところです。

ロールのインストール

見つけたロールは ansible-galaxy コマンドで手元の環境にインストールすることができます。このコマンドはAnsibleをインストールしていれば使用可能です。

$ ansible-galaxy install JasonGiedymin.nodejs -p provisioning/roles

-pオプションでインストール先をprovisioning/rolesに指定しています。この指定がない場合は/opt/local/etc/ansible/roles/にインストールされます。

provisioning/nodejsservers.yml

nodejsservers.ymlにインストールしたロールを追加します。

---
- hosts: nodejsservers
  sudo: yes
  roles:
    - JasonGiedymin.nodejs

プロビジョニングの実行

これで全ての準備が整いました。ansible-playbookで実行です。

$ ansible-playbook -i provisioning/development provisioning/site.yml -u vagrant

上のコマンドを実行すると、次のような結果が表示されます。

PLAY [nodejsservers] ************************************************************* 

GATHERING FACTS *************************************************************** 
The authenticity of host '192.168.33.10 (192.168.33.10)' can't be established.
RSA key fingerprint is 10:13:56:d6:97:3e:66:25:01:c8:98:58:e0:75:63:e6.
Are you sure you want to continue connecting (yes/no)? yes
ok: [192.168.33.10]

TASK: [JasonGiedymin.nodejs | Install Debian packages] ************************ 
skipping: [192.168.33.10]

TASK: [JasonGiedymin.nodejs | Install RedHat packages] ************************ 
failed: [192.168.33.10] => (item=wget,curl,gcc-c++,gcc) => {"failed": true, "item": "wget,curl,gcc-c++,gcc"}
msg: Failure talking to yum: Cannot retrieve repository metadata (repomd.xml) for repository: extras. Please verify its path and try again

FATAL: all hosts have already failed -- aborting

PLAY RECAP ******************************************************************** 
           to retry, use: --limit @/Users/moongift/site.retry

192.168.33.10              : ok=1    changed=0    unreachable=0    failed=1   

エラーが出ます。どうもyum周りで問題発生のようです。

yumの問題を修正するロールの作成

原因としては/etc/yum.repos.d/CentOS-Base.repoの内容に問題があるため必要なyumのパッケージをインストールできないようです。

以下の行を

http://ftp.riken.jp/Linux/centos/6.5/updates/x86_64/repodata/repomd.xml

次のように修正すれば問題解決です。

http://ftp.riken.jp/Linux/centos/6/updates/x86_64/repodata/repomd.xml

これはfix-yum-cent-os-repoと言うアドホックなロールを作って直すことにします。

provisioning/roles/fix-yum-cent-os-repo/tasks/main.yml

---
- name: yum.repos.d/CentOS-Base.repo is fixed
  replace: dest=/etc/yum.repos.d/CentOS-Base.repo regexp="\$releasever" replace="6"

provisioning/nodejsservers.yml

nodejsservers.ymlに追加します。

---
- hosts: nodejsservers
  sudo: yes
  roles:
    - fix-yum-cent-os-repo
    - JasonGiedymin.nodejs

再度プロビジョニングの実行

今度こそ準備が整いました。再びansible-playbookです。

$ ansible-playbook -i provisioning/development provisioning/site.yml -u vagrant

この実行結果は次のようになりました。

PLAY [nodejsservers] ************************************************************* 

GATHERING FACTS *************************************************************** 
ok: [192.168.33.10]

TASK: [fix-yum-cent-os-repo | yum.repos.d/CentOS-Base.repo is fixed] ********** 
changed: [192.168.33.10]

TASK: [JasonGiedymin.nodejs | Install Debian packages] ************************ 
skipping: [192.168.33.10]

TASK: [JasonGiedymin.nodejs | Install RedHat packages] ************************ 
changed: [192.168.33.10] => (item=wget,curl,gcc-c++,gcc)

TASK: [JasonGiedymin.nodejs | Checking installed version of nodejs] *********** 
failed: [192.168.33.10] => {"changed": true, "cmd": "/usr/bin/test \"$(/usr/local/bin/node -v 2> /dev/null)\" = v0.10.36", "delta": "0:00:00.003732", "end": "2015-01-17 09:34:59.096592", "rc": 1, "start": "2015-01-17 09:34:59.092860", "stdout_lines": []}
...ignoring

TASK: [JasonGiedymin.nodejs | Download nodejs v0.10.36] *********************** 
changed: [192.168.33.10]

TASK: [JasonGiedymin.nodejs | Verify SHASUM of nodejs v0.10.36] *************** 
changed: [192.168.33.10]

TASK: [JasonGiedymin.nodejs | Unpack nodejs v0.10.36] ************************* 
changed: [192.168.33.10]

TASK: [JasonGiedymin.nodejs | Compile and install nodejs v0.10.36] ************ 
changed: [192.168.33.10]

TASK: [JasonGiedymin.nodejs | NPM Install global packages] ******************** 
failed: [192.168.33.10] => (item=nodemon) => {"failed": true, "item": "nodemon"}
msg: Failed to find required executable npm
failed: [192.168.33.10] => (item=debug) => {"failed": true, "item": "debug"}
msg: Failed to find required executable npm
failed: [192.168.33.10] => (item=foreman) => {"failed": true, "item": "foreman"}
msg: Failed to find required executable npm

FATAL: all hosts have already failed -- aborting

PLAY RECAP ******************************************************************** 
           to retry, use: --limit @/Users/moongift/site.retry

192.168.33.10              : ok=8    changed=7    unreachable=0    failed=1   

またしてもエラーです。yumの問題はクリアしましたが、今度はsudoした際にnpmのパスが通っていないことに原因があるようです。

sudo時にパスを引き継ぐためのロールを作成

再びパッチ的なロールを作ります。

provisioning/roles/keep-user-path-in-sudo/tasks/main.yml

---
- name: keep $PATH for sudo
  lineinfile: dest=/etc/sudoers state=present line='Defaults    env_keep += "PATH"'

- name: disable secure_path for sudo
  lineinfile: dest=/etc/sudoers state=absent line='Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin'

provisioning/nodejsservers.yml

nodejsservers.ymlに追加します。

---
- hosts: nodejsservers
  sudo: yes
  roles:
    - fix-yum-cent-os-repo
    - keep-user-path-in-sudo
    - JasonGiedymin.nodejs

三度プロビジョニングの実行

今度こそ準備が整いました。三度 ansible-playbook を実行します。

$ ansible-playbook -i provisioning/development provisioning/site.yml -u vagrant

今度の結果は次のようになります。

PLAY [nodejsservers] ************************************************************* 

GATHERING FACTS *************************************************************** 
ok: [192.168.33.10]

TASK: [fix-yum-cent-os-repo | yum.repos.d/CentOS-Base.repo is fixed] ********** 
ok: [192.168.33.10]

TASK: [keep-user-path-in-sudo | keep $PATH for sudo] ************************** 
changed: [192.168.33.10]

TASK: [keep-user-path-in-sudo | disable secure_path for sudo] ***************** 
changed: [192.168.33.10]

TASK: [JasonGiedymin.nodejs | Install Debian packages] ************************ 
skipping: [192.168.33.10]

TASK: [JasonGiedymin.nodejs | Install RedHat packages] ************************ 
ok: [192.168.33.10] => (item=wget,curl,gcc-c++,gcc)

TASK: [JasonGiedymin.nodejs | Checking installed version of nodejs] *********** 
ok: [192.168.33.10]

TASK: [JasonGiedymin.nodejs | Download nodejs v0.10.36] *********************** 
skipping: [192.168.33.10]

TASK: [JasonGiedymin.nodejs | Verify SHASUM of nodejs v0.10.36] *************** 
skipping: [192.168.33.10]

TASK: [JasonGiedymin.nodejs | Unpack nodejs v0.10.36] ************************* 
skipping: [192.168.33.10]

TASK: [JasonGiedymin.nodejs | Compile and install nodejs v0.10.36] ************ 
skipping: [192.168.33.10]

TASK: [JasonGiedymin.nodejs | NPM Install global packages] ******************** 
changed: [192.168.33.10] => (item=nodemon)
changed: [192.168.33.10] => (item=debug)
changed: [192.168.33.10] => (item=foreman)

PLAY RECAP ******************************************************************** 
192.168.33.10              : ok=7    changed=3    unreachable=0    failed=0   

エラーが出ずに完了しました。

変数でロールの動作を変更する

Node.jsのバージョン確認

さて一応Node.jsはセットアップできました。

しかしセットアップした仮想マシン上でNode.jsのバージョンを確認してみると・・・

$ node -v
v0.10.36

少しバージョンが古いですね。

これを安定版の現時点での最新のものにバージョンアップしてみましょう。

JasonGiedymin.nodejsのvarsの確認

このロールではインストールするNode.jsのバージョンを変数で定義しているので、実はロールの内容を書き換えるなど面倒なことをしなくてもバージョンアップが可能です。

JasonGiedymin.nodejsの変数の内容を確認してみると以下のように動的に取得する仕組みになっています。

$ cat provisioning/roles/JasonGiedymin.nodejs/vars/main.yml 

nodejs_playbook_version: "0.1.5"
nodejs_version_tag: "v{{nodejs_version}}"
nodejs_file_tag: "node-{{nodejs_version_tag}}"
nodejs_file_name: "{{nodejs_file_tag}}.tar.gz"
nodejs_base_url: "http://nodejs.org/dist/v{{nodejs_version}}/"
nodejs_tarball_url: "{{nodejs_base_url}}{{nodejs_file_name}}"
nodejs_shasum_url: "{{nodejs_base_url}}SHASUMS.txt"
m

これらの変数や設定はプレイブックや独自のロールで上書きすることができます。厳密には上書きではなく先に評価される場所に書いたものが有効になります。詳細は公式のドキュメントで確認してください。

なお変数は vars/main.yml ではなくデフォルト変数として defaults/main.yml などに定義されていることもあります。違いは簡単に言うとインベントリファイルの中で上書きできるか否かということになります。これに関しても詳細は公式のドキュメントで確認できます。

プレイブック内で変数の指定

今回はトップレベルのプレイブックで変数を指定するとしましょう。

provisioning/nodejsservers.yml

- hosts: nodejsservers
  sudo: yes
  roles:
    - fix-yum-cent-os-repo
    - keep-user-path-in-sudo
    - JasonGiedymin.nodejs
  vars:
    nodejs_version: "0.12.7"

または

---
- hosts: nodejsservers
  sudo: yes
  roles:
    - fix-yum-cent-os-repo
    - keep-user-path-in-sudo
    - { role: JasonGiedymin.nodejs, nodejs_version: "0.12.7" }

でもOKです。

実行&確認

今まで通りにansible-playbookを実行したら仮想マシンにログインしてNode.jsのバージョンを確認してみてください。

$ node -v
v0.12.7

ちゃんと指定したバージョンがインストールされているのが確認できました。

終わりに

今回は軽くAnsible Galaxyを利用してロールの再利用を試してみました。

選んだロールが意外とすんなり動かず「楽々〜」というのは少々タイトル詐欺になってしまった感がありますが、こういうことは実際に使ってみると多々あることなので、動かないものを動くように調整するところから実践してみました。

なお、こうしたトラブルはAnsibleだからではなく、Chefのクックブックでもしばしばあります。このあたりはセットアップ環境が様々なので致し方ないでしょう。ただ一からロールを作るよりは楽になるはずです。

今回は問題の解決に環境を調整するというアプローチを取りましたが、ロールの方を修正するという手もあります。Ansible Galaxyにロールを登録するためには必ずGitHubのリポジトリでロールを管理する必要がありますので、そのリポジトリをフォークして修正したり、その内容をフィードバックすることも簡単に行えます。

Ansible Galaxyを利用したロールの再利用は、本格的にAnsibleを運用していく上では不可欠といってもいい要素です。是非うまく使いこなして快適なAnsibleライフを送ってください!

Ansible Galaxy | Find, reuse, and share the best Ansible content