いいかげん日記

思いついたことをただひたすら書き殴るいいかげんな日記です。

【CentOS × Ansible × serverspec】ansible-playbookからserverspecをインストールできない

はじめに

書籍『DevOps導入指南』に沿ってローカル環境でDevOpsっぽいツールのエコシステムを構築しようと思い立ち、2019年のお盆休みに作業を開始したものの、全367ページ中82ページにして早くも「Ansibleのplaybookからserverspecをインストールできない」というハプニングが発生。疑問に思った私は、この書籍の発行日を確認したところ、「2016年10月13日 初版 第1刷発行」と書かれていたのであった。。。

環境

CentOS 7.6.1810
Vagrant 2.2.5
Ansible 2.8.2

問題

書籍『DevOps導入指南』のp.82のコマンド

$ ansible-playbook -i development site.yml --diff

を実行すると、以下のエラーが発生。(実際には--diffオプションは使っていない結果ですが。。)

[DEPRECATION WARNING]: The TRANSFORM_INVALID_GROUP_CHARS settings is set to allow bad characters in group names by 
default, this will change, but still be user configurable on deprecation. This feature will be removed in version 
2.10. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
 [WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details


PLAY [webservers] **************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************
ok: [localhost]

TASK [common : install epel] ***************************************************************************************
ok: [localhost]

TASK [nginx : install nginx] ***************************************************************************************
changed: [localhost]

TASK [nginx : replace index.html] **********************************************************************************
changed: [localhost]

TASK [nginx : nginx start] *****************************************************************************************
changed: [localhost]

TASK [serverspec : install ruby] ***********************************************************************************
changed: [localhost]

TASK [serverspec : install serverspec] *****************************************************************************
changed: [localhost] => (item=rake)
failed: [localhost] (item=serverspec) => {"ansible_loop_var": "item", "changed": false, "cmd": "/bin/gem install --no-user-install --no-document serverspec", "item": "serverspec", "msg": "ERROR:  Error installing serverspec:\n\tnet-ssh requires Ruby version >= 2.2.6.", "rc": 1, "stderr": "ERROR:  Error installing serverspec:\n\tnet-ssh requires Ruby version >= 2.2.6.\n", "stderr_lines": ["ERROR:  Error installing serverspec:", "\tnet-ssh requires Ruby version >= 2.2.6."], "stdout": "Successfully installed rspec-support-3.8.2\nSuccessfully installed rspec-core-3.8.2\nSuccessfully installed diff-lcs-1.3\nSuccessfully installed rspec-expectations-3.8.4\nSuccessfully installed rspec-mocks-3.8.1\nSuccessfully installed rspec-3.8.0\nSuccessfully installed rspec-its-1.3.0\nSuccessfully installed multi_json-1.13.1\n", "stdout_lines": ["Successfully installed rspec-support-3.8.2", "Successfully installed rspec-core-3.8.2", "Successfully installed diff-lcs-1.3", "Successfully installed rspec-expectations-3.8.4", "Successfully installed rspec-mocks-3.8.1", "Successfully installed rspec-3.8.0", "Successfully installed rspec-its-1.3.0", "Successfully installed multi_json-1.13.1"]}

PLAY RECAP *********************************************************************************************************
localhost                  : ok=6    changed=4    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0 

原因

エラーメッセージに注目。

"msg": "ERROR:  Error installing serverspec:\n\tnet-ssh requires Ruby version >= 2.2.6."

この本に沿って環境構築を進めると、rubyのバージョンが古すぎてserverspecが入らないようです。

$ ruby --version
ruby 2.0.0p648 (2015-12-16) [x86_64-linux]


あと、冒頭に出てくるWarningも気になるので対応したい。
現在のAnsibleではgroup名の書き方が厳格になっているらしく、そのあたりでWarningが出ている模様。

結論

~/ansible-playbook-sample/roles/serverspec/tasks/main.ymlを下記のように変更する。

---
# tasks file for serverspec
- name: exist ruby
  shell: bash -lc 'which ruby'
  register: ruby_install
  failed_when: ruby_install.rc not in [0,1]

- name: install rbenv
  git:
    repo: https://github.com/sstephenson/rbenv.git
    dest: /usr/local/rbenv
    update: no

- name: install ruby-build
  git:
    repo: https://github.com/sstephenson/ruby-build.git
    dest: /usr/local/rbenv/plugins/ruby-build
    update: no

- name: add rbenv path
  blockinfile:
    path: /etc/profile.d/rbenv.sh
    block: |
      export RBENV_ROOT="/usr/local/rbenv"
      export PATH="/usr/local/rbenv/bin:$PATH"
      eval "$(rbenv init -)"
    create: yes

- name: reflesh login shell
  shell: bash -lc 'source /etc/profile.d/rbenv.sh'

- name: run install.sh
  shell: bash -l '/usr/local/rbenv/plugins/ruby-build/install.sh'
  become: true

- name: install package-related-ruby
  yum:
    name:
      - bzip2
      - gcc
      - openssl-devel
      - readline-devel
      - zlib-devel
    state: installed

- name: install ruby 2.6.3
  shell: bash -lc "rbenv install 2.6.3 && rbenv rehash && rbenv global 2.6.3"
  when: ruby_install.rc == 1

- name: provisioning gem
  shell: bash -lc 'rbenv shell 2.6.3'
  when: ruby_install.rc == 1

- name: install rake
  gem:
    name: rake
    state: present
    executable: /usr/local/rbenv/shims/gem

- name: install serverspec
  gem:
    name: serverspec
    state: present
    user_install: no
    executable: /usr/local/rbenv/shims/gem


その他、~/ansible-playbook-sample/developmentと~/ansible-playbook-sample/productionの中のgroup名にある記述を下記のように変更。

  • development-servers --> development_servers
  • production-serveres --> production_servers

さらに、~/ansible-playbook-sample/group_varsのファイル名を変更。

  • development-servers.yml --> development_servers.yml
  • production-servers.yml --> production_servers.yml


これでOK。

あ、ひとつ注意。
このplaybookを回したあと、手動でserverspec-initを立ち上げるときは一度仮想環境からexitして再ログインが必要です。
これね↓

[vagrant@**** ~]$ exit   
$ vagrant ssh

対策の概要

エラー対策

  • rubyのバージョンを指定してインストール
    1. rbenvのインストール
    2. ruby-buildのインストール
    3. rubyの依存パッケージのインストール
    4. 指定バージョンのrubyをインストール
  • rake & serverspecをインストール

Warning対策

  • group名の"-"(ハイフン)を"_"(アンダースコア)に置換

ポイント

  • pathの管理

これが混乱の元凶。Ansibleはroot権限で実行するようだが、rbenvはそれ自身がRBENV_ROOTなるpathを持っているようで、思ったように動作してくれず大いに悩んだ。

  • インストール先の設定

root権限だけであれば機能するplaybookを作れたのだが「全ユーザで手動でもserverspecをいじれるようにしたい!」と欲張ったために更に時間がかかった。。

rbenvのインストール

- name: install rbenv
  git:
    repo: https://github.com/sstephenson/rbenv.git
    dest: /usr/local/rbenv
    update: no

全ユーザに適用するために、インストール先を/usr/local/rbenvに指定。

[ruby][rbenv][System Wide Install]全ユーザーrubyを使えるようにする – ADACHIN SERVER LABO
CentOS7 全体でユーザ共通に使える rbenv をインストールする - らくがきちょう
システムワイドにrbenvを入れる - 私事ですが……

ruby-buildのインストール

- name: install ruby-build
  git:
    repo: https://github.com/sstephenson/ruby-build.git
    dest: /usr/local/rbenv/plugins/ruby-build
    update: no

こちらは/<rbenvのインストール先>/plugins/ruby-buildにインストールしないと、あとでrbenvに「installなんて知らない!」と怒られる。

rbenvとruby-buildインストール時に no such command `install' が出た原因と対処法 - Javaエンジニア、React+Redux+Firebaseでアプリを作る


- name: add rbenv path
  blockinfile:
    path: /etc/profile.d/rbenv.sh
    block: |
      export RBENV_ROOT="/usr/local/rbenv"
      export PATH="/usr/local/rbenv/bin:$PATH"
      eval "$(rbenv init -)"
    create: yes

- name: reflesh login shell
  shell: bash -lc 'source /etc/profile.d/rbenv.sh'

- name: run install.sh
  shell: bash -l '/usr/local/rbenv/plugins/ruby-build/install.sh'
  become: true


この設定にかなり手間取った。
まだ混乱や冗長な部分もあると思うけど、一番のポイントはたぶん、/etc/profile.d/rbenv.shを作り、そこでRBENV_ROOTを指定すること。
これを設定しないばっかりに、「rbenvなんてない!」と怒られまくりました。。

AnsibleでRuby環境構築 - Qiita

rubyの依存パッケージのインストール

- name: install package-related-ruby
  yum:
    name:
      - bzip2
      - gcc
      - openssl-devel
      - readline-devel
      - zlib-devel
    state: installed

rubyをインストールする前に依存パッケージをインストールしないと怒られる。
これは調べればすぐに出てきたし、そこまで難しくなかったかな。

指定バージョンのrubyをインストール

- name: install ruby 2.6.3
  shell: bash -lc "rbenv install 2.6.3 && rbenv rehash && rbenv global 2.6.3"
  when: ruby_install.rc == 1

- name: provisioning gem
  shell: bash -lc 'rbenv shell 2.6.3'
  when: ruby_install.rc == 1

この記述自体はすぐに分かったんだけど、その前のpath設定が難しすぎていつもここでansibleが止まったので色々といじりまわした部分。
結果、ここが原因ではなかったという。。

rake & serverspecをインストール

- name: install rake
  gem:
    name: rake
    state: present
    executable: /usr/local/rbenv/shims/gem

- name: install serverspec
  gem:
    name: serverspec
    state: present
    user_install: no
    executable: /usr/local/rbenv/shims/gem


途中、rakeのインストールはどのユーザでも使えるのにserverspecはうまくいかない謎の現象が発生し混乱した部分。
調べると、serverspecはデフォルトインストールだと/rootの中に入っちゃうらしく、user_installをnoに設定して解決。
これにも意外と時間を使ってしまった。。

まとめ

この記事もまだ整理しきれておらず、記述に混乱があると思われます。
また、結論に記載したタスクも冗長な部分が残っていると思います。
というのも、1つの問題に対する対策が新たな問題を引き起こし、二重三重の対策を施すうちにどの対策がどの問題を解決したか、あるいは、どの問題が未然に防がれたかがもはや把握できていなくなったからです。笑
まぁ、でも、ひとまずこれでまた本に沿って次に進めるようになりました。

DevOpsへの道は険しいなぁ。。

DevOps導入指南 Infrastructure as Codeでチーム開発・サービス運用を効率化する (DEV Engineer’s Books)

DevOps導入指南 Infrastructure as Codeでチーム開発・サービス運用を効率化する (DEV Engineer’s Books)