Ansibleでrbenvのplaybookを書いてハマったことなど
あらすじ
新規にAWSでRailsアプリをホストするぞ、となったリア充は、dockerでプロビジョニングのデバッグ環境を作ったものの「プロビジョニングツールはChefでいいのか?」という迷いが常にあった。このタイミングでかねてから耳にしていたfabricとAnsibleを試してみた結果、Ansibleがたいそう気に入ったのでChefでいうCookBook的な位置づけであるPlaybookを書く運びとなったのであった。
本格的にplaybookを書くにあたって
- ベストプラクティスを読んでおすすめディレクトリ構造などを把握する
- Best Practices — Ansible Documentation
- ぼくが知ってるChefとたいして変わらない
- playbookを書くためのエディタを用意する
- テスト環境は前述のdockerで作ったCentOSを使う
- sshで繋げられる状態になっていればソロもゼロもいらない。そう、Ansibleならね。
前回はhostsとymlファイル1つを同じディレクトリに置いただけのシンプルな構成だったけど、今後複数のplaybookを管理していく上で、ベストプラクティスに沿ったかたちにしてみた結果、こんな感じになった。
最終的には環境とか役割ごとに処理を変えるためのファイルとかあるので、そういうのが入ってくると思われるが、現時点で必要なものだけだとこんなもん。
rbenvのplaybook
全体的な構成については、現状は最初期のものだし、まだまだわかってないことも多いので、このあたりは雰囲気だけにしてrbenvのplaybookの話をする。
前提
- rbenvはシステムワイドにインストールする
- rubyはcentosユーザーでインストールする
- 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