Ansibleでgem installする時の注意

Ansibleでgem installしても、参照出来なくて困った時の話。

Playbook

とりあえず、Playbookを貼ります。。

---
- hosts: all
  become: false
  tasks:
    - name: Download rbenv
      git:
        repo: https://github.com/rbenv/rbenv.git
        dest: /home/vagrant/.rbenv
        update: no
    - name: Download rbenv-build
      git:
        repo: https://github.com/sstephenson/ruby-build.git
        dest: /home/vagrant/.rbenv/plugins/ruby-build
        update: no
    - name: Set rbenv environment
      register: result
      changed_when: '"Set rbenv environment" in result.stdout'
      shell: |
        if [ "$(grep rbenv ${HOME}/.bashrc)" == "" ]; then
          echo 'Set rbenv environment'
          echo 'export PATH="${HOME}/.rbenv/shims:${HOME}/.rbenv/bin:${PATH}"' >> ${HOME}/.bashrc
        fi
    - name: Install ruby
      register: ruby_installer_result
      changed_when: '"Installing ruby" in ruby_installer_result.stdout'
      shell: |
        if [ "$(rbenv versions 2>&1 | grep 2.4.1)" == "" ]; then
          echo 'Installing ruby 2.4.1'
          ${HOME}/.rbenv/bin/rbenv install 2.4.1
          ${HOME}/.rbenv/bin/rbenv global 2.4.1
          ${HOME}/.rbenv/bin/rbenv rehash
        fi
    - name: Install bundler
      gem:
        name: bundler
        state: present
        executable: ${HOME}/.rbenv/shims/gem
        version: 1.15.3
    - name: Install rails
      gem:
        name: rails
        state: present
        executable: ${HOME}/.rbenv/shims/gem
        version: 5.1.3

余りキレイな書き方ではないのですが、

  1. ホームディレクトリ配下にrbenvをインストール
  2. ruby-buildを追加
  3. rbenv周りの環境変数を.bashrcに追記
  4. Rubyのインストール
  5. bundlerのインストール
  6. railsのインストール

をしているだけです。
このPlaybookを実行しても、bundleやrailsが見つかりません。
が、gem listにはあったのです。

まさか…

–user-install

gem listにあるということは、どこかにインストールはされているわけです。
今の設定で、参照出来なくてインストールされているとなると、可能性が高いのは、–user-installオプションをつけてインストールしているときです。

AnsibleのgemモジュールのOptionsを見てみます。

–user-installに該当するオプションがありますね。
user_installです。
どうやら、デフォルト値がtrueになっているようです。

ということは、これをfalseで指定してあげればいいですね。

---
- hosts: all
  become: false
  tasks:
    - name: Download rbenv
      git:
        repo: https://github.com/rbenv/rbenv.git
        dest: /home/vagrant/.rbenv
        update: no
    - name: Download rbenv-build
      git:
        repo: https://github.com/sstephenson/ruby-build.git
        dest: /home/vagrant/.rbenv/plugins/ruby-build
        update: no
    - name: Set rbenv environment
      register: result
      changed_when: '"Set rbenv environment" in result.stdout'
      shell: |
        if [ "$(grep rbenv ${HOME}/.bashrc)" == "" ]; then
          echo 'Set rbenv environment'
          echo 'export PATH="${HOME}/.rbenv/shims:${HOME}/.rbenv/bin:${PATH}"' >> ${HOME}/.bashrc
        fi
    - name: Install ruby
      register: ruby_installer_result
      changed_when: '"Installing ruby" in ruby_installer_result.stdout'
      shell: |
        if [ "$(rbenv versions 2>&1 | grep 2.4.1)" == "" ]; then
          echo 'Installing ruby 2.4.1'
          ${HOME}/.rbenv/bin/rbenv install 2.4.1
          ${HOME}/.rbenv/bin/rbenv global 2.4.1
          ${HOME}/.rbenv/bin/rbenv rehash
        fi
    - name: Install bundler
      gem:
        name: bundler
        state: present
        executable: ${HOME}/.rbenv/shims/gem
        user_install: false # 追記
        version: 1.15.3
    - name: Install rails
      gem:
        name: rails
        state: present
        executable: ${HOME}/.rbenv/shims/gem
        user_install: false # 追記
        version: 5.1.3

これで期待するところにインストールされるようになりました。
一安心一安心

VirtualBox Guest AdditionsをインストールするPlaybook

VirtualBox Guest AdditionsをCentOS公式のBoxにインストールするで書いた手順をPlaybook化。
もう少しマシな方法があるんだろうけど、とりあえずはこれで。

---
- hosts: all
  become: true
  become_user: root
  tasks:
    - name: Get VBoxClient path
      changed_when: false
      shell: command -v VBoxClient
      register: vboxclient_result
    - name: Download VBoxGuestAddition
      get_url:
        url: http://download.virtualbox.org/virtualbox/5.1.26/VBoxGuestAdditions_5.1.26.iso
        force: no
        dest: /root/VBoxGuestAddition.iso
      when: vboxclient_result.stdout == ""
    - name: Mount VBoxGuestAddition directory
      mount:
        path: /mnt
        src: /root/VBoxGuestAddition.iso
        opts: loop
      when: vboxclient_result.stdout == ""
    - name: Install VBoxGuestAddition
      script: /mnt/VBoxLinuxAdditions.run
      when: vboxclient_result.stdout == ""
    - name: Unmount VBoxGuestAddition directory
      mount:
        path: /mnt
        state: absent
      when: vboxclient_result.stdout == ""
    - name: Delete VBoxGuestAddition.iso
      file:
        path: /root/VBoxGuestAddition.iso
        state: absent
      when: vboxclient_result.stdout == ""

/vagrantにマウントしない時のやり方と注意

CentOS公式のBoxを使い、/vagrantに現在のディレクトリをマウントしない時のVagrantfileについてのメモ。

/vagrantではなく他のディレクトリにマウントする

/vagrantではなく他のディレクトリに、現在のディレクトリをマウントする時は、2つやることがある。
/appにマウントする想定で話を進める。

  • /vagrantへマウントしないようにするsynced_folderを定義する
  • /appへマウントするsynced_folderを定義する

/vagrantへマウントしないようにするsynced_folderを定義する

前者についてだが、明示的に/vagrantへのsynced_folderを定義しなくても、勝手にマウントしようとする。
これが非常に厄介だ。
そうさせないために、/vagrantへマウントしないsynced_folderを定義する必要がある。

config.vm.synced_folder '.', '/vagrant', disabled: true

最後のdisabled: trueがミソである。
こう書くことで、/vagrantへマウントしなくなる。

/appへマウントするsynced_folderを定義する

これは簡単。

config.vm.synced_folder '.', '/app', type: :nfs

これで/appにマウントされる。

ansible_localで構成管理する

ansible_localで構成管理する時で、/vagrantへマウントさせないとエラーを吐く。
ansible_localを指定した時は、/vagrantをカレントディレクトリとしてplaybookに指定されたファイルを探しに行く。
以下のような場合は、/vagrant/playbooks/ruby.ymlを探しに行ってしまう。

config.vm.provision "ruby", type: "ansible_local" do |ansible|
  ansible.playbook = 'playbooks/ruby.yml'
  ansible.install = true
end

んじゃ、どうしたらカレントディレクトリを変更できるか。
Vagrantのドキュメントにあるprovisioning_pathに、そのディレクトリを指定すれば良い。

config.vm.provision "ruby", type: "ansible_local" do |ansible|
  ansible.playbook = 'playbooks/ruby.yml'
  ansible.install = true
  ansible.provisioning_path = '/app'
end

/vagrantにマウントしない時なんてそうそうないんだけど、そういうことがあれば注意していきたい。

最後に

他にも注意点はあると思うけど、今日ハマったことはこんなところなので、とりあえずこんなもんで。

早い話、provisionで/vagrantを/appにリンクさせればいいんだけどね。

VagrantのAnsible Local Provisionerの実行ユーザー

開発環境は、Vagrantで構築することが多くなりました。
Vagrantでは、Ansible Local Provisionerという機能があり、VMへのAnsibleのインストールやPlaybookに従って構成管理出来ます。
そう、Ansibleの実行時にハマりました。

要点だけ書くと、remote_userで実行ユーザーを指定しても、そのユーザーで実行されないのです。
例えば、以下のようなplaybookだと、systemdモジュールのところでエラーになります。(Boxはcentos/7

- hosts: all
  remote_user: root
  become: false
  tasks:
    - name: install epel-release
      yum:
        name: epel-release
        state: present
      become: true
    - name: update packages
      yum:
        name: '*'
        state: latest
      become: true
    - name: install yum-utils
      yum:
        name: yum-utils
        state: present
      become: true
    - name: install device-mapper-persistent-data
      yum:
        name: device-mapper-persistent-data
        state: present
      become: true
    - name: install lvm2
      yum:
        name: lvm2
        state: present
      become: true
    - name: add docker repo
      shell: 'yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo'
      args:
        chdir: '/etc/yum.repos.d'
        creates: docker-ce.repo
      become: true
    - name: install docker-ce
      yum:
        name: docker-ce
        state: present
      become: true
    - name: restart docker
      systemd:
        name: docker.service
        state: restarted
        daemon_reload: yes
        enabled: yes
      changed_when: false
      become: true

remote_userでrootを指定しているので成功するように思ってたんですが、これじゃダメでした。
これだ!っていう情報が見つからなかったですが、何を指定しようとvagrantユーザーで実行されます。
そのため、

  • sudoで実行する必要がある箇所にのみ、become: trueをつける
  • トップレベルでbecome: trueにし、sudoで実行する必要がないところだけbecome: falseにする

あたりが、落としどころこかなぁと思いつつ。