読者です 読者をやめる 読者になる 読者になる

リア充爆発日記

You don't even know what ria-ju really is.

Ansibleでrbenvのplaybookを書いてハマったことなど

あらすじ

新規にAWSRailsアプリをホストするぞ、となったリア充は、dockerでプロビジョニングのデバッグ環境を作ったものの「プロビジョニングツールはChefでいいのか?」という迷いが常にあった。このタイミングでかねてから耳にしていたfabricとAnsibleを試してみた結果、Ansibleがたいそう気に入ったのでChefでいうCookBook的な位置づけであるPlaybookを書く運びとなったのであった。

本格的にplaybookを書くにあたって

  • ベストプラクティスを読んでおすすめディレクトリ構造などを把握する
  • playbookを書くためのエディタを用意する
    • ymlとディレクトリ構造を扱えるやつだったらなんでもいいと思うけどリア充おすすめはAtomだ。
  • テスト環境は前述のdockerで作ったCentOSを使う
    • sshで繋げられる状態になっていればソロもゼロもいらない。そう、Ansibleならね。

前回はhostsとymlファイル1つを同じディレクトリに置いただけのシンプルな構成だったけど、今後複数のplaybookを管理していく上で、ベストプラクティスに沿ったかたちにしてみた結果、こんな感じになった。 f:id:ria10:20150414125400p:plain

最終的には環境とか役割ごとに処理を変えるためのファイルとかあるので、そういうのが入ってくると思われるが、現時点で必要なものだけだとこんなもん。

rbenvのplaybook

全体的な構成については、現状は最初期のものだし、まだまだわかってないことも多いので、このあたりは雰囲気だけにしてrbenvのplaybookの話をする。

前提

  • rbenvはシステムワイドにインストールする
  • rubycentosユーザーでインストールする
  • rbenvグループを作って、rbenvを使うユーザー(centosユーザだけだけど)はrbenvグループに追加する

全処理内容

  • group_vars/all
ruby_version: 2.2.2
rbenv_root: /usr/local/rbenv
os_user: centos
  • roles/rbenv/tasks/main.yml
---
- name: Install dependencies
  sudo: yes
  yum: pkg={{item}} state=latest
  with_items:
    - git
    - tar
    - gcc
    - make
    - libffi-devel
    - zlib-devel
    - openssl-devel

- name: Install ruby
  sudo: yes
  yum: name=ruby state=latest

- name: Install rbenv
  sudo: yes
  git: repo=https://github.com/sstephenson/rbenv.git dest={{ rbenv_root }}

- name: Install ruby-build
  sudo: yes
  git: repo=https://github.com/sstephenson/ruby-build.git dest={{ rbenv_root }}/plugins/ruby-build

- name: create rbenv group
  sudo: yes
  group: name=rbenv state=present

- name: add user to rbenv group
  sudo: yes
  user: name=centos append=yes groups=rbenv
  register: add_group

- name: create shims dir
  sudo: yes
  file: path={{ rbenv_root }}/shims state=directory

- name: create versions dir
  sudo: yes
  file: path={{ rbenv_root }}/versions state=directory

- name: change owner of install dir
  sudo: yes
  command: chgrp -R rbenv {{ rbenv_root }}

- name: change mode of install dir
  sudo: yes
  command: chmod -R g+rwxXs {{ rbenv_root }}

- name: Set rbenv env file
  sudo: yes
  copy: src=rbenv.sh dest=/etc/profile.d mode=0775

- name: Install ruby with rbenv
  shell: bash -lc "CONFIGURE_OPTS="--disable-install-rdoc" rbenv install {{ ruby_version }}"

- name: "set ruby {{ ruby_version }} for system"
  shell: bash -lc "rbenv global {{ ruby_version }} && rbenv rehash"

  • roles/rbenv/files/rbenv.sh
export RBENV_ROOT=/usr/local/rbenv
export PATH="$RBENV_ROOT/bin:$PATH"
eval "$(rbenv init -)"

内容としては、これで問題なんだけど、これだけだと実はうまくいかない(環境によるかも)。 centosユーザーをrbenvグループに追加したあとのタスクは、centosユーザーがrbenvグループに属していることを前提としているが、rbenvグループへの追加処理が反映されないで後続の処理が行われてしまうためだ。

Ansibleなどを通さずに手動で同じ手続きを踏む場合、グループへの追加処理は、一度ログアウトしてログインしてセッションを新たにしないと反映されない。

Ansibleの挙動自体は、タスクごとにコネクションを貼り直しているので、問題ないのだけどOpenSSHのControlMasterという機能が働いているとコネクションをキャッシュしてしまって想定した挙動にならないというのがポイントで、これを回避するためにログインしたままセッションを貼り直す(何いってるのかわからない)、もしくは、グループ追加を反映する手段を探してみたが、そういう方法はないみたいだった。

そこでどうするかというとControlMasterを切る、という方法で、ここで前述のツリー構造にあるansible.cfgを使う。

[ssh_connection]
ssh_args= -o ControlMaster=no

これで毎回新たにコネクションが貼り直されるので、処理がうまくいくのであった。 ただ、大量のサーバで大量のタスクをさばく場合、このオーバーヘッドはバカにならない可能性があるので、使いドコロは考えたほうがいいとは思う。

ansible.cfgについては、こちらを参照すべし。

The Ansible Configuration File — Ansible Documentation