yujiro's blog

「インターネット上で正しい答えを得る最善の方法は、質問することではない。間違った答えを投稿することだ」by ウォード・カニンガム

Ansible で Ubuntu16.04に Rails, MySQL5.6, NodeJS 用の開発環境を作成する

今までchefを使っていたのだけれど、知り合いから手軽でオススメ & python製 と聞きつけて試してみたらすごく気に入った。

王道なrails開発環境用のplaybook(chefでいうcookbook)を紹介してみようと思う。 macにansibleを入れて、ubuntu16.04 の仮想マシンに対してコードを実行する。

ruby2.3.1 (rbenv経由)

mysql5.6

node.js の最新版

が入ります。

(以下をかなり参考にさせていただきました!)

GitHub - katsuhiko/template-rails-ansible: Template for Ruby on Rails App Developmettem by Ansible

Ansibleについて

chefのようなpull型と違い、push型なのでsshで対象サーバに繋げてコードを実行するという形。

chefの場合、クライアントにログインした後、chef-clientをインストールしてサーバー側に問い合わせをしてコードを実行する。 対してansibleはクライアント側にはpython2を入れるだけでよい。

python2はサーバーosに最初から入っていることが多く、その場合クライアント側には何もインストールする必要がない。

そのため、依存が少ないので手軽でエラーが少ない。

chefが難しいといわれる理由の一つは、クライアント側にインストールするchef-clientや、ホスト側のchefやその他の依存ライブラリのバージョンによってエラーが出たりするのでそこら辺ではないかなと思う。

また、knifeだったり、berkshelfだったり、その他の登場人物が多いことも複雑だと感じる理由だと思う。

もちろんそうであるがために大規模なサーバーの構成を管理する分にはchefは向いていると思う。

ansibleはpython2のみでシンプルに動き、構成もシンプルなので学習コストが低い。

小〜中規模ぐらいのインフラ管理には非常に向いている印象。

インストール & 紹介

ansibleのインストール

$ brew install ansible

終了。

あとは playbook を作成していくって感じです。

今回は僕のリポジトリにあるやつを参考にしながら紹介していきます。

$ git clone https://github.com/bamboo-yujiro/ansible_my_rails

してください。

(以下をかなり参考にさせていただきました!)

GitHub - katsuhiko/template-rails-ansible: Template for Ruby on Rails App Developmettem by Ansible

下記のようになってます。

.
├── README.md
├── ansible.cfg
├── develop.retry
├── develop.yml
├── hosts.sample
└── roles
    ├── mysql
    │   ├── handlers
    │   │   └── main.yml
    │   ├── tasks
    │   │   └── main.yml
    │   └── templates
    │       ├── my-develop.cnf.j2
    │       ├── my.cnf.j2
    │       └── mysql.cnf.j2
    ├── nodejs
    │   └── tasks
    │       └── main.yml
    ├── prepare_rails
    │   └── tasks
    │       └── main.yml
    └── rbenv
        ├── defaults
        │   └── main.yml
        └── tasks
            └── main.yml

ansible.cfg は 全体の設定みたいなものだと認識してます。

[defaults]
roles_path = roles/
hostfile = hosts

ミドルウェアは roles にディレクトリをきって配置することが多いみたい。 hostfile というのは マシン の接続情報を書きます。 以下な感じになってます。

[web]
web-01 ansible_ssh_host=192.168.33.92 ansible_ssh_user=ubuntu ansible_ssh_private_key_file=~/machines/hoge/.vagrant/machines/default/virtualbox/private_key

見ての通り、host名(ip address) と ssh するユーザー、秘密鍵のパスを記載します。パスワード認証だったら ansible_ssh_pass でいけるみたいです。

hosts を記載したら

$ ansible -i hosts all -m ping

と実行してみます。

web-01 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}

みたいに帰ってきたらOKです


次に、develop.yml ですが、これが playbook になります。名前はなんでも構いません。

playbook の実行は以下のようにしてできます。

$ ansible-playbook develop.yml

中身は実行対象のhostsや、task、role を記述していきます。 Ubuntu16.04 には デフォルトで Python2 が入っていないため、コマンド1発でいれちゃいます。

...
  tasks:
  - name: install python 2
    become: yes
    raw: test -e /usr/bin/python || (apt -y update && apt install -y python-minimal)

become: yes ってのは sudo 権限で実行するということです。

そのあとはroles に記載されている tasks を順番に実行していきます。

...
- name: Build a Rails development environment
  hosts: web
  become: yes

  roles:
    - mysql
    - rbenv
    - nodejs
    - prepare_rails

hosts の指定ができるのに注目です。

例えば、本番環境で使用する場合なんかは、host を何台かにわけて redis 用 だとか webサーバ用ってな感じに容易にわけられます。


では、roles についてです。

tasks には main.yml というファイルを置きます。 こいつをみて task を実行していきます。

mysql の task は以下になっています。

---
- name: Add repository for mysql
  apt_repository: repo='deb http://archive.ubuntu.com/ubuntu trusty universe' state=present

- name: Install mysql
  apt: name={{ item }} state=latest
  with_items:
    - mysql-server-5.6
    - mysql-client-5.6
    - python-mysqldb

- name: Set mysql service to start on boot
  service: name=mysql state=started enabled=true

- name: Remove my.cnf
  file:
    state: absent
    path: /etc/alternatives/my.cnf
  file:
    state: absent
    path: /etc/mysql/my.cnf.fallback

- name: Put my.cnf
  template: src=my.cnf.j2 dest=/etc/mysql/my.cnf backup=true mode=0644

- name: Put my-develop.cnf
  template: src=my-develop.cnf.j2 dest=/etc/mysql/conf.d/my-develop.cnf backup=true mode=0644

- name: Put mysql.cnf
  template: src=mysql.cnf.j2 dest=/etc/mysql/conf.d/mysql.cnf backup=true mode=0644
  notify: restart mysql

- name: Set the root privileges
  mysql_user:
    user: root
    host: "{{ item }}"
    password: ""
  with_items:
   - "%"
   - 127.0.0.1
   - ::1
   - localhost

まず、Ubuntu16.04 では 普通にapt すると MySQL 5.7 が入るので、add-repository を実行させてます。

そのあと、 apt-get ですね。

with_items に記載されている パッケージをループして apt-get します。 こうすればパッケージ毎にブロックを記述しなくてもよくなります。

state=latest

は インストールするパッケージの中で、最新版を常にインストールするということです。 current だと、既にインストールされていればskip します。

Remove my.cnf の部分はかなり暫定的な対応になってます。

なんか、MySQL5.6はmy.cnfシンボリックリンクになっていて、 その他にもmy.cnf.fallbackとかいう意味不明なファイルがあり普通に cnf ファイルなどを配置してもうまくいかなかったので。

こちらは時間あるときに調べます。もしくは詳しい方いたらおしえてください。

その後にtemplate を配置していきます。

一番最後に notify ってのがあるんですが、これは以下の通りです。

今回は Ansible の Playbook で使える notify と handlers の使い方について調べてみる。 このふたつはペアになっていて、タスクに notify を書いておくと、そのタスクで状態に変更があった場合にそれと対応する handlers が実行される仕組みになっている。

ここではmysql デーモンを restart したいので handlers にある main.yml

---
- name: restart mysql
  service: name=mysql state=restarted

これを実行させます。

最後にroot のパスワードを設定する記述がありますが、これも with_items でループして、各 host に対してパスワード設定してます。

って所です。

nodejs のtaskは「冪等性」が一切ない感じになってるのでここでは紹介しませんw

最新版をインストールしたくて、実行コマンドは

Ubuntuに最新のNode.jsを難なくインストールする - Qiita

を参考にして command というもので直にコマンドを実行しているだけです。

これももっといいやつを模索します。

prepare_rails は mysql2 や imagemagick のgem をいれるのに必要なパッケージをインストールするtask があるだけです。