サイト名変更・お引越しのお知らせ

AnsibleでWEBアプリケーション(Rails)環境構築チュートリアル

今回はAnsibleでWEBアプリケーション(Rails)環境を構築してみましょう。

ゴール
  • Ansibleを理解できる
  • Ansibleを実戦で使えるようになる

Ansibleをまだ触ったことがない方は、こちらの記事でまずは全体感を理解してみてください。

モグモグさん

他の言語やフレームワークの環境にも応用できるので、

Ansibleを使えるようになりたい方みなさんにおすすめです。

手順の確認

今回はRuby on Railsで作ったサービスを動かすための環境を作ります。

そのためには、今回下記の手順を実行する必要があります。

  1. Linuxユーザーを追加
  2. Gitの追加
  3. Rubyの追加
  4. Node.jsの追加
  5. 追加したRoleが動作しているかを確認

実際にアプリケーションを構築するときに使えるような構成になっていますので一緒に手を動かしつつ、やっていきましょう!

環境構築

まずはAnsibleを実行するための環境構築をしていきます。

今回はVagrantで環境を作っていきましょう。

Vagrantについてはこちらの記事を参考にしてください。

vagrant up で仮想サーバーを立ててssh vagrantで接続できるようになっているところまで進めてみましょう。

補足

Ansibleが実行できる環境であれば、DockerでもEC2でもなんでも大丈夫です!

Ansibleを実装

動作環境は作成できたので、実際にAnsibleをガシガシ書きながら環境を構築していきたいと思います。

Inventoryファイルの作成

Inventoryファイルを作成していきましょう。

今回はvagrantで作った環境に向けてAnsibleを流していくので、

hostsというファイルでvagrantサーバーを指定しましょう。

[local]
vagrant

Playbookの作成

続いてlocal.ymlというPlaybookを作成していきましょう。

- name: Playbook for web server
  hosts: local
  become: yes
  remote_user: vagrant

動作確認のために、Ansibleを流してみましょう

$ ansible-playbook -i hosts local.yml

rolesを追加していないので何も起こらないですが、下記のようにokになっていればvagrantに接続できていますし、Ansibleも動いているのでバッチリです。

PLAY [Playbook for web server] *****************************************************************************************************************************************************************************

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

PLAY RECAP *************************************************************************************************************************************************************************************************
vagrant                    : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Linuxユーザーの作成

続いてユーザーを作成していきましょう。

まずはroles/user/tasks/main.ymlを作成します。

- name: Add groups
  group:
    name: '{{ item.name }}'
  with_items: '{{ group_list }}'

# admin
- name: Add admin users
  user:
    name: '{{ item.name }}'
    group: admin
    groups: admin,wheel
    password: "{{ item.password | password_hash('sha512') }}"
    update_password: on_create
  with_items: '{{ admin_users }}'

- name: Add keys of admin users
  authorized_key:
    user: '{{ item.name }}'
    key: "{{ lookup('file', 'roles/user/public_keys/'+ item.name + '.key.pub') }}"
  with_items: '{{ admin_users }}'

- name: Add permissions to admin
  lineinfile:
    dest: /etc/sudoers
    backup: yes
    line: '%admin ALL=(ALL) NOPASSWD: ALL'

# developer
- name: Add developer users
  user:
    name: '{{ item.name }}'
    group: developer
    password: "{{ item.password | password_hash('sha512') }}"
    update_password: on_create
  with_items: '{{ developer_users }}'

- name: Add keys of developer users
  authorized_key:
    user: '{{ item.name }}'
    key: "{{ lookup('file', 'roles/user/public_keys/'+ item.name + '.key.pub') }}"
  with_items: '{{ developer_users }}'

基本的にAnsibleを書いていくときには、公式のドキュメントを参考に書いていきます。

参考 DocumentationAnsible

例えば今回、userというmoduleを使っていますが、下記の点を確認していきます。

  • どんなmoduleなのか
  • どんなパラメーターが使えるのか

user_moduleのドキュメント

重要ポイント

公式のドキュメントを読んで実装していけば、他のmoduleも自在に扱えるようになり、応用が効くようになります。

Ansible用語整理

ここで簡単にAnsibleの用語の説明です。

コメントで基本を説明しているので読みつつ、ざっと理解してみてください。

このあたりがわかっていればあとはmodule次第なので他でも応用できます。

- name: Add groups // タスク単位の説明。ここではグループを追加するという意味。
  group: // module。ここではgroupというmoduleを使っている。
    name: '{{ item.name }}' // ループ処理の一つの値からデータを取得。ここではname。
  with_items: '{{ group_list }}' // with_itemsを使うとループ処理ができる。

admin_usersgroup_listがありますが、それらは変数になっていて別ファイルから参照します。

直接書いても問題ないですが、ファイルに分けたほうが可読性や柔軟性が増します

vars.ymlを作成して変数の実際のデータを作成していきましょう。

group_list:
  - { name: 'admin' }
  - { name: 'developer' }

admin_users:
  - { name: 'admin1', password: 'password' }
  - { name: 'admin2', password: 'password' }

developer_users:
  - { name: 'developer1', password: 'password' }

そして、local.ymlvars.ymlを参照するように追記します。

 - name: Playbook for web server
    hosts: local
    become: yes
    remote_user: vagrant
    vars_files: vars.yml // 追加箇所

続いて秘密鍵と公開鍵のセットを作成しましょう。(メールアドレスの箇所はお好きなアドレスにしてください)

$ ssh ~/.ssh

$ ssh-keygen -t rsa -b 4096 -C "hogehoge@gmail.com" -f ansible-sample -m PEM

これで、ansible-sampleという名前の秘密鍵と公開鍵のセットができていると思います。

ユーザーごとに公開鍵を追加するタスクは下記のようになっていますので
roles/user/public_keysに公開鍵を追加しましょう。

ユーザーごとにname.key.pubとしてそれぞれ置いておきたいですが
今回は、先ほど作った鍵をそれぞれのユーザーのものとして作成しておきましょう。

- name: Add keys of admin users
  authorized_key:
    user: '{{ item.name }}'
    key: "{{ lookup('file', 'roles/user/public_keys/'+ item.name + '.key.pub') }}"
  with_items: '{{ admin_users }}'

$ ls roles/user/public_keys を実行した時に、

admin1.key.pub admin2.key.pub developer1.key.pubのように出力されていれば大丈夫です。

これでグループの追加と、admin1, admin2developer1というユーザーを追加するrolesができました。

それでは実行する前に、local.ymlに作成したroleを追加しましょう。

- name: Playbook for web server
  hosts: local
  become: yes
  remote_user: vagrant
  vars_files: vars.yml
  roles: // ここから追加箇所
    - user

準備できましたので実行しましょう。

$ ansible-playbook -i hosts local.yml

PLAY [PlayBook for web server] ***********************************************************************************************************************************************************************************************************************************************

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

TASK [user : Add groups] *****************************************************************************************************************************************************************************************************************************************************
ok: [vagrant] => (item={'name': 'admin'})
ok: [vagrant] => (item={'name': 'developer'})

TASK [user : Add admin users] ************************************************************************************************************************************************************************************************************************************************
ok: [vagrant] => (item={'name': 'admin1', 'password': 'password'})
ok: [vagrant] => (item={'name': 'admin2', 'password': 'password'})

TASK [user : Add keys of admin users] ****************************************************************************************************************************************************************************************************************************************
changed: [vagrant] => (item={'name': 'admin1', 'password': 'password'})
changed: [vagrant] => (item={'name': 'admin2', 'password': 'password'})

TASK [user : Add permissions to admin] ***************************************************************************************************************************************************************************************************************************************
ok: [vagrant]

TASK [user : Add developer users] ********************************************************************************************************************************************************************************************************************************************
ok: [vagrant] => (item={'name': 'developer1', 'password': 'password'})

TASK [user : Add keys of developer users] ************************************************************************************************************************************************************************************************************************************
changed: [vagrant] => (item={'name': 'developer1', 'password': 'password'})

PLAY RECAP *******************************************************************************************************************************************************************************************************************************************************************
vagrant                    : ok=7    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

okと出力されているので成功です。

グループとユーザーが作成できました。

Gitの追加

こちらは必須ではないですが追加しておきましょう。

まずはGit用のrolesの追加です。

$ mkdir -p roles/git/tasks

- name: Install git
  yum: // yum moduleを利用
    name: git
    state: present
    lock_timeout: 180 

それでは作成したroleをlocal.ymlに例のごとく追加しましょう。

- name: Playbook for web server
  hosts: local
  become: yes
  remote_user: vagrant
  vars_files: vars.yml
  roles: 
    - user
    - git // ここから追加箇所

実行しましょう。

$ ansible-playbook -i hosts local.yml

Rubyの追加

それでは続いてRubyのrolesを作成して、アプリケーションが動く環境を作りましょう!

まずはディレクトリをtask用とtemplate用を作成しておきましょう。

$ mkdir -p roles/ruby/tasks

$ mkdir roles/ruby/templates

続いてmain.ymlを作成していきます。

- name: Install packages
  yum:
    name: '{{ item }}'
    state: latest
    lock_timeout: 180
  with_items:
    - openssl-devel
    - sqlite-devel
    - gcc
    - gcc-c++
    - readline-devel
    - mysql
    - mysql-devel
    - libselinux-python

- name: Install rbenv
  git:
    repo: https://github.com/sstephenson/rbenv.git
    dest: /usr/local/rbenv

- name: Edit bashrc
  template:
    src: roles/ruby/templates/rbenv_system.sh.j2
    dest: /etc/profile.d/rbenv.sh
    owner: '{{ app_user }}'
    group: '{{ app_group }}'

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

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

- name: Set default Ruby version
  shell: bash -lc "rbenv global {{ ruby_version }} && rbenv rehash"

- name: Install bundler and so on
  shell: bash -lc "gem install {{ item }}"
  with_items:
    - rbenv-rehash
    - bundler
    - rails

だんだん読めてきましたか?

基本的にはmoduleを利用しているので不明な箇所はリファレンスを確認して記述パターンを理解していくと良いと思います。

ここでapp_userapp_groupruby_versionは変数を参照しているので追加しましょう。

app_user: developer1 // 追加箇所
app_group: developer // 追加箇所
ruby_version: 2.5.3 // 追加箇所
group_list:
  - { name: 'admin' }
  - { name: 'developer' }

admin_users:
  - { name: 'admin1', password: 'password' }
  - { name: 'admin2', password: 'password' }

developer_users:
  - { name: 'developer1', password: 'password' }

taskの中で、roles/ruby/templates/rbenv_system.sh.j2を参照している箇所があるのでそのファイルも作成しておきます。

主にrbenvを使えるようにする設定ですね。

メモ
rbenvはRubyのバージョンを管理するツールです。

それをユーザー共通の箇所に置いています。

export RBENV_ROOT="/usr/local/rbenv"
export PATH="${RBENV_ROOT}/bin:${PATH}"
eval "$(rbenv init -)"

それではlocal.ymlに作成したroleを追加します。

- name: Playbook for web server
  hosts: local
  become: yes
  remote_user: vagrant
  vars_files: vars.yml
  roles:
    - user
    - git
    - ruby // 追加箇所

実行しましょう!

$ ansible-playbook -i hosts local.yml

Ruby環境ができました。

Node.jsの追加

最後のセクションです。

Node.jsを追加していきましょう。

まずはディレクトリの作成です。

$ mkdir -p roles/nodejs/tasks

タスクを書いていきましょう!

- name: Setup nodejs8.x
  shell: curl -sL https://rpm.nodesource.com/setup_8.x | sudo -E bash -

- name: Installing latest version of node.js
  yum:
    name: nodejs
    state: latest
    lock_timeout: 180

- name: Install yarn package
  get_url: url="https://dl.yarnpkg.com/rpm/yarn.repo" dest=/etc/yum.repos.d/yarn.repo

- name: Installing yarn
  yum:
    name: yarn
    state: latest
    lock_timeout: 180

作成したroleを追加します。

- name: Playbook for web server
  hosts: local
  become: yes
  remote_user: vagrant
  vars_files: vars.yml
  roles:
    - user
    - git
    - ruby
    - nodejs  // 追加箇所

実行しましょう。

$ ansible-playbook -i hosts local.yml

成功すれば完了です!

追加したRoleが動作しているかを確認

まずは、追加したユーザーでSSHできるかどうかを確認しましょう。

~/.ssh/configで、Userをadmin1に変更し、IdentityFileを作成した秘密鍵に変更しましょう。(ansible-sample)

Host vagrant
  HostName 127.0.0.1
  User admin1
  Port 2222
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile ~/.ssh/ansible-sample
  IdentitiesOnly yes
  LogLevel FATAL

SSHしてみましょう!

$ ssh vagrant                                                                                                                                                                       
[admin1@localhost ~]$

作成したユーザーでSSHできました。

~/.ssh/configのUserを変更しadmin2でもdeveloper1でもSSHしてみてください。

続いて、追加したGitとRubyとNode.jsが入っているか確認しましょう。

$ ssh vagrant

Gitの確認

[admin1@localhost ~]$ git --version
git version 1.8.3.1

Rubyの確認

[admin1@localhost ~]$ ruby -v
ruby 2.5.3p105 (2018-10-18 revision 65156) [x86_64-linux]

Node.jsの確認

[admin1@localhost ~]$ node -v
v8.16.0

ちゃんとインストールされていますね。

もしCommand not foundなどが出力された場合、改めて手順を確認してみてください

これでRailsを動かすための環境が作れました。

まとめ

お疲れ様でした!

Ansibleを利用して、Rails環境を構築できました。

この手順を応用すればいろいろな環境ができますし、環境を変更する時もコードをベースとして変更が可能になります。