Ansibleでrootユーザーにrvmを入れて、gemをインストールするタスクでどハマりしたのでまとめ。
クライアントはCentOS7です。
Ansibleのバージョンは以下の通り。
$ ansible --version
ansible 1.8.4 (release1.8.4 ebc8d48d34) last updated 2015/04/11 16:37:11 (GMT +900)
lib/ansible/modules/core: (detached HEAD 5f58240d17) last updated 2015/04/11 16:34:18 (GMT +900)
lib/ansible/modules/extras: (detached HEAD 4048de9c1e) last updated 2015/04/11 16:34:25 (GMT +900)
v2/ansible/modules/core: (detached HEAD 34784b7a61) last updated 2015/04/11 16:34:34 (GMT +900)
v2/ansible/modules/extras: (detached HEAD 21fce8ac73) last updated 2015/04/11 16:34:41 (GMT +900)
configured module search path = /usr/share/ansible
だめだったパターン
以下のようなPlaybookを用意して、
## role/rvm/task/main.yml
# prepare for building Ruby
- name: be sure ruby basic package is installed
yum: name={{ item }} conf_file=/etc/yum.conf.noexclude enablerepo=epel state=present
with_items:
- gcc-c++
- patch
- readline
- readline-devel
- zlib
- zlib-devel
- libyaml-devel
- libffi-devel
- openssl-devel
- make
- bzip2
- autoconf
- automake
- libtool
- bison
- sqlite-devel
- postgresql-devel
ignore_errors: yes
# install RVM and Ruby
- name: install rvm
shell: curl -sSL https://get.rvm.io | bash creates=/usr/local/rvm/LICENSE
sudo: yes
changed_when: False
- name: check ruby version
command: /bin/bash -l -c "which ruby"
register: ruby_version_check
changed_when: '"/usr/local/rvm/rubies/ruby-{{ rvm_ruby_version }}/bin/ruby" not in ruby_version_check.stdout'
sudo: yes
ignore_errors: yes
always_run: yes
- name: install ruby
command: /bin/bash -l -c "rvm install {{ rvm_ruby_version }} && rvm --default {{ rvm_ruby_version }}"
sudo: yes
when: ruby_version_check|changed
notify:
- rvm_cleanup
- name: install postgres(gem)
command: gem install postgres -v 0.7.9.2008.01.28 creates=/usr/local/rvm/gems/ruby-{{ rvm_ruby_version }}/gems/postgres-0.7.9.2008.01.28
sudo: yes
----------------
## host_vers/test-server
rvm_ruby_version: "1.8.7-p374"
ansible-playbookコマンドを実行したところ、以下のようなエラーが出現しました。
failed: [test.bacchi.me] => {"changed": true, "cmd": ["gem", "install", "postgres"], "delta": "0:00:06.624956", "end": "2015-05-13 19:27:08.330638", "rc": 1, "start": "2015-05-13 19:27:01.705682", "warnings": []}
stderr: ERROR: Error installing postgres:
ERROR: Failed to build gem native extension.
/usr/bin/ruby extconf.rb
mkmf.rb can't find header files for ruby at /usr/share/include/ruby.h
Gem files will remain installed in /usr/local/share/gems/gems/pg-0.18.1 for inspection.
Results logged to /usr/local/share/gems/gems/pg-0.18.1/ext/gem_make.out
stdout: Building native extensions. This could take a while...
FATAL: all hosts have already failed -- aborting
あれー、rubyのpathが /usr/bin/ruby になってる・・
rubyコマンドをフルパスで指定して、再度実行
rubyのパスがパッケージで入れたrubyのパスになっていたので、
rvmで入れたRubyのフルパスを指定して、再度ansible-playbookを実行。
playbookはこんな感じ。
- name: install postgres(gem)
command: /usr/local/rvm/rubies/ruby-{{ rvm_ruby_version }}/bin/gem install postgres -v 0.7.9.2008.01.28 creates=/usr/local/rvm/gems/ruby-{{ rvm_ruby_version }}/gems/postgres-0.7.9.2008.01.28
sudo: yes
しかし、同様のエラーが・・
failed: [test.bacchi.me] => {"changed": true, "cmd": ["/usr/local/rvm/rubies/ruby-1.8.7-p374/bin/gem", "install", "postgres"], "delta": "0:00:06.624956", "end": "2015-05-13 19:27:08.330638", "rc": 1, "start": "2015-05-13 19:27:01.705682", "warnings": []}
stderr: ERROR: Error installing postgres:
ERROR: Failed to build gem native extension.
/usr/bin/ruby extconf.rb
mkmf.rb can't find header files for ruby at /usr/share/include/ruby.h
Gem files will remain installed in /usr/local/share/gems/gems/pg-0.18.1 for inspection.
Results logged to /usr/local/share/gems/gems/pg-0.18.1/ext/gem_make.out
stdout: Building native extensions. This could take a while...
FATAL: all hosts have already failed -- aborting
解決策
調べてみると sudo は.sudoを実行したユーザの環境変数が引き継がれないので、一工夫してやる必要がありました。
sudo の -i オプションを使って環境変数を読み込んでやれば /etc/profile を読み込んでくれて、
rvmでインストールしたrubyを使ってくれるようになりました。
それを踏まえて、rubyのバージョン確認のタスクと、gemインストールのタスクを
sudo モジュールを「sudo: no」とし、rvmで入ったコマンドを叩く時に sudo -i env を
かませることで、想定通りの動きをしてくれるようになりました。
また、「sudo: no」を書いてやるのもポイントです。
gemをフルパスで記述したのにインストールに失敗した理由
フルパスでgemコマンド叩いた時もインストールできなかったのはgemがrubyを呼び出す時に、
環境変数を参照してrubyを呼び出しているため、パッケージ版のrubyが呼び出されていました。
おまけ 完成形のplaybook
## role/rvm/task/main.yml
# prepare for building Ruby
- name: be sure ruby basic package is installed
yum: name={{ item }} conf_file=/etc/yum.conf.noexclude enablerepo=epel state=present
with_items:
- gcc-c++
- patch
- readline
- readline-devel
- zlib
- zlib-devel
- libyaml-devel
- libffi-devel
- openssl-devel
- make
- bzip2
- autoconf
- automake
- libtool
- bison
- sqlite-devel
- postgresql-devel
ignore_errors: yes
# install RVM and Ruby
- name: install rvm
shell: curl -sSL https://get.rvm.io | bash creates=/usr/local/rvm/LICENSE
sudo: yes
changed_when: False
- name: check ruby version
command: sudo -i /bin/bash -l -c "which ruby"
register: ruby_version_check
changed_when: '"/usr/local/rvm/rubies/ruby-{{ rvm_ruby_version }}/bin/ruby" not in ruby_version_check.stdout'
sudo: no
ignore_errors: yes
always_run: yes
- name: install ruby
command: /bin/bash -l -c "rvm install {{ rvm_ruby_version }} && rvm --default {{ rvm_ruby_version }}"
sudo: yes
when: ruby_version_check|changed
notify:
- rvm_cleanup
- name: install postgres(gem)
command: sudo -i gem install postgres -v 0.7.9.2008.01.28 creates=/usr/local/rvm/gems/ruby-{{ rvm_ruby_version }}/gems/postgres-0.7.9.2008.01.28
sudo: no