いまさらながらAnsibleを使ってみた

世の中もうDockerの時代なのかもしれませんが、ある案件で使うサーバーのプロビジョニングツールとしてAnsibleを使ってみました。

f:id:yuum3:20170824145026p:plain

今まではChefを使っていましたがChefはRubyでガリガリ書けるので何でもできますが、メンテや構成管理情報を伝えるのに難があるかなと思ます。そこでシンプルという噂のAnsibleを使って、Ruby on Railsの動くサーバーを構築するAnsibleを書いてみました。

本家のドキュメント もちゃんとしてますし、ネット上にはたくさんの情報があるので楽に作れましたがそれでも何点か苦労したのでそこを中心に書きます。Playbooksは以下のようにroleに分けて書きました。

├── roles
│   ├── apps
│   │   ├── files
│   │   │   ├── logrotate
│   │   │   └── unicorn
│   │   └── tasks
│   │       └── main.yml
│   ├── linux
│   │   └── tasks
│   │       └── main.yml
│   ├── nginx
│   │   ├── files
│   │   │   └── logrotate
│   │   ├── handlers
│   │   │   └── main.yml
│   │   ├── tasks
│   │   │   └── main.yml
│   │   └── templates
│   │       └── recorder.j2
│   ├── postgresql
│   │   └── tasks
│   │       └── main.yml
│   └── ruby
│       └── tasks
│           └── main.yml
└── site.yml

1. Linux(Unbuntu)の基本設定

てこずったのは、locale の設定。localeの作成やtimezoneの設定はmoduleがあるのに、locale設定は無いので update-locale コマンドを使いました。コマンドを使うと問題になるのが、どうやって冪等にするか。 update-locale は毎回実行されても問題はありませんが、Ansibleの勉強をかねて調べました。

ansible_env.LANGでターゲット側の環境変数が参照できます。ただしLANGが無い場合エラーになるのでデフォルト値を設定しました。

- name: install tools
  apt: name={{ item }} update_cache=yes
  with_items:
    - git
    - language-pack-ja

- name: create locale ja_JP.UTF-8
  locale_gen:
    name: ja_JP.UTF-8

- name: set locale to ja_JP.UTF-8
  command: update-locale LANG=ja_JP.UTF-8
  when: ansible_env.LANG | default('') != 'ja_JP.UTF-8'

- name: set timezone to Asia/Tokyo
  timezone:
    name: Asia/Tokyo

- name: install and start NTP
  apt: name=ntp

2. Rubyのインストール

これはネット上の情報で出来ました。Rubyのバーション番号等のパラメター(変数)は他の場所で定義した方が良いかもしれませんが、とりあえず同一ファイルに定義しました。

今回は /usr/local/binruby, gem … をインストールしたのですが、 gem module は user_install: no を設定しないと /usr/local/bin に入らないのでハマりました

- name:  define ruby version
  set_fact:
    workspace: /usr/local/src
    ruby_version: 2.4.1
    ruby_download_url: http://cache.ruby-lang.org/pub/ruby/2.4/ruby-2.4.1.tar.gz

- name: install packages required to build ruby
  apt: "name={{ item }} state=present"
  with_items:
    - build-essential
    - zlib1g-dev
    - libssl-dev
    - libyaml-dev
    - libreadline6-dev
    - zlib1g-dev
    - libncurses5-dev
    - libffi-dev
    - libgdbm3
    - libgdbm-dev
    - libsqlite3-dev

- name: download ruby
  get_url:
    url: "{{ ruby_download_url }}"
    dest: "{{ workspace }}/ruby-{{ ruby_version }}.tar.gz"

- name: extract ruby
  unarchive:
    src: "{{ workspace }}/ruby-{{ ruby_version }}.tar.gz"
    dest: "{{ workspace }}/"
    copy: no

- name: build ruby
  command: >
    {{ item }}
    chdir={{ workspace }}/ruby-{{ ruby_version }}
    creates=/usr/local/bin/ruby
  with_items:
    - ./configure --disable-install-doc
    - make
    - make install
    - gem update --system

- name: install bundler gem
  gem:
    name: bundler
    user_install: no

3. PostgreSQL

PostgreSQLはUbuntu16.04標準の9.5ではなく、 9.6を入れたかったので apt_repository , apt_key を設定しました。
また、ログインアカウントでpsqlを使えるようにしたかったので pg_hba.conf を書き換えています。その後のPostgreSQL再起動はnotifyだと非同期になるので serviceで行いました。ここの冪等もAnsibleの勉強になりました ^^;

- name: add PostgreSQL repositories
  apt_repository:
    repo: deb http://apt.postgresql.org/pub/repos/apt/ xenial-pgdg main
    state: present

- name: add PostgreSQL key
  apt_key:
    url: https://www.postgresql.org/media/keys/ACCC4CF8.asc
    state: present

- name: install PostgreSQL
  apt: name={{ item }} update_cache=yes
  with_items:
    - postgresql-9.6
    - postgresql-client-9.6
    - postgresql-contrib-9.6
    - libpq-dev
    - python3-psycopg2

- name: configure PostgreSQL (authentication)
  replace:
    path: /etc/postgresql/9.6/main/pg_hba.conf
    regexp: '^local(\s.+?\s+)peer$'
    replace: 'local\1trust  # peer #'
  register: pg_hba_file

- name: restart PostgreSQL server
  service:
    name: postgresql
    state: restarted
  when: pg_hba_file.changed

- name: add user to PostgreSQL
  postgresql_user:
    name: XXXXXX
    password: XXXXXX
    role_attr_flags: CREATEDB,NOSUPERUSER

- name: add databases to PostgreSQL
  postgresql_db:
    name: XXXXXX
    owner: XXXXXX

4. Nginx

Nginx はネット上にあった情報でなんとかなりました

- name:  define nginx values
  set_fact:
    conf_file: /etc/nginx/sites-available/XXXXXX
    site_name: XXXXXX
    ssl: false
    unicorn_socket: unix:/tmp/unicorn.XXXXXX.socket
    public_path: /home/apps/XXXXXX/current/public

- name: install Nginx
  apt: name={{ item }} update_cache=yes
  with_items:
    - nginx
    - apache2-utils

- name: set this-site configuration
  template:
    src: ../templates/XXXXXX.j2
    dest: "{{ conf_file }}"
  notify: restart nginx

- name: disbale default configuration
  file:
    path: /etc/nginx/sites-enabled/default
    state: absent
  notify: restart nginx

- name: enable this-site configuration
  file:
    dest: /etc/nginx/sites-enabled/XXXXXX
    src:  "{{ conf_file }}"
    state: link
  notify: restart nginx

- name: set log rotation
  copy:
    src: ../files/logrotate
    dest: /etc/logrotate.d/nginx
    owner: root
    mode: 0644

5. アプリケーション

Ruby on Railsアプリケーション用の設定も簡単でした。ちなみにRails等のインストールはデプロイ時に行われるのでありません。

- name: make directory of application
  file:
    path: /home/apps/XXXXX
    state: directory
    owner: ubuntu
    group: ubuntu
    mode: 0755

- name: set unicorn configuration
  copy:
    src: ../files/unicorn
    dest: /etc/init.d/unicorn
    mode: 0755

- name: enable unicorn service
  service:
    name: unicorn
    enabled: yes
    use: service

- name: set log rotation
  copy:
    src: ../files/logrotate
    dest: /etc/logrotate.d/unicorn
    owner: root
    mode: 0644

感想

出来たplaybookを見るとChefに比べ短くシンプルですね。あまり難しい事をしないならAnsibleは楽です。ただし冪等を頑張ると少したいへんかも・・・・