Embulk構築作業を自動化してみた

#はじめに 

みなさん！メリー、ファッキン、クリスマス！！！！
アイスタイル　アドベントカレンダー22日目は、
クリスマスに暗い部屋で一人TVはつけたまま震えてる系インフラエンジニア @sugimotor が、
ここ1ヵ月くらいで取り組んだembulkの構築自動化取り組みについて、
ちょいとしたtips・ハマったとこなどを交えつつテキトーに書いていきます。


#概要
##embulkとは
[Fluentdのバッチ版Embulk(エンバルク)のまとめ](https://qiita.com/hiroysato/items/397f36c4838a0a93e352)にだいたい書いてあります。
今回は自動化の取り組みなので詳細は割愛しますが。弊社では異種間DBデータ抽出を行い、
そのデータをBigqueryにインポートしている部分で利用しています。
![Embulk01jpg.jpg](https://qiita-image-store.s3.amazonaws.com/0/195967/70451b6a-dd44-d86b-3827-4d8058d50868.jpeg)


#背景

きっかけはBIチームからのembulkの困ってる事の相談でした。

- 今後頻繁なサーバスケールアウトが発生しそう。
- 手作業でembulk gemのパッケージをインストールしてるがめんどくさい(パッケージのバージョンは指定)
- 手作業でSSHファイルのコピー&配布がめんどｋ（ｒｙ
- 手作業でembulk⇒各DBサーバの疎通テスト作業を実施するのが（ｒｙ

じゃあ自動化しようぜ！って事で今回はこのうち、
> - 手作業でembulk gemのパッケージをインストール(パッケージのバージョンは指定)
> - 手作業でSSHファイルのコピー&配布
> - 手作業でembulk⇒各DBサーバの疎通テスト作業を実施する。

の部分をツールを用いて自動化をすることにしました。
行く行くはDocker化して動かすのがいいんじゃないかという話が出てましたが、
ボリューム的に大きくなってしまうので、今回ひとまず手作業の自動化をゴールに置いて進めることにしました。

# 使ったもの
シェルやfablicなどで自動化するのもありだったんですが、
今回は下記２つのツールを使いました。

##Ansible
基本的にアイスタイル現行環境ではchefを利用していましたが、

 - 今回のサーバ規模に対してchefのcookbook構造が大きすぎる
 - 内容がシンプルなので分かりやすく、誰でも保守が容易になる。

といった理由からAnsibleを利用する事に決定しました。

##ServerSPEC
こちらは元々サーバ構築後のチェックに使っていたこともあり、
今回Ansibleで構築した内容のチェックとembulk⇒各DBサーバの疎通テスト作業を実施する部分でのチェックに利用する事にしました。

# 実践

おおまかにやっていく手順として、

1. ServerSPECでテストを作成
2. Ansible-playbookを作成(修正)
3. playbookをサーバに対して実行
4. ServerSPECを実行
5. ServerSPECでFAILが発生したらAnsibleを修正
6. 2に戻る(繰り返す)

というTDDに則る形で、作成したplaybook、ServerSPECファイルはすべてgitにぶち込んで作成を行っていきました。
各ツールでのポイントなどは下記となります。

##　ServerSPEC
テスト内容としては下記のテストをServerSPECにて行いました。

1. Embulk Gemがインストールされている事
2. liquidファイルが配置されている事
3. 操作を行うユーザが配置されている事

大体はServerSPECのデフォルトで容易されているResource Typeで対応できましたが、
ServerSPECの`describe package`にて対応したいと思っていましたが、
Embulk Gemに対応したpackageコマンドが無かったので、
[こちら](http://kamatama41.hatenablog.com/entry/2015/10/16/202614)を参考にコマンドを追加しました。

```ruby:default_spec.example.rb
########################################
###embulkプラグインパッケージテスト用###
########################################
class Specinfra::Command::Base::Package
  class << self
    def check_is_installed_by_embulk_gem(name, version=nil)
      regexp = "^#{name}"
      cmd = "/home/hoge/.embulk/bin/embulk gem list --local | grep -iw #{(regexp)}"
      cmd = %Q!#{cmd} | grep -w -- "[( ]#{escape(version)}[,)]"! if version
      cmd
    end
  end
end

#######################################
####embulkプラグインインストール確認###
#######################################

%w{
	embulk-decoder-commons-compress
}.each do |package|
describe package("#{package}") do
  let(:disable_sudo) { true }
  it { should be_installed.by('embulk_gem') }
  end
end

```

テストはこんな感じでざっと書いてしまい、続いてAnsibleの整備を行いました。

## サーバ構成管理

Ansibleディレクトリ構成をこんな感じで作成。
とりあえずベストプラクティスに則て作ってみましたが、現在の規模だと`tasks/main.yml`以外はほとんど使いませんでした。

```shell:directory
embulk/
|-- README.md
|-- defaults
|   `-- main.yml
|-- handlers
|   `-- main.yml
|-- meta
|   `-- main.yml
|-- tasks
|   `-- main.yml  ===> mainのplaybook
|-- tests
|   |-- inventory
|   `-- test.yml
`-- vars
    `-- main.yml 

```

Ansibleのplay-bookでは下記を行いました。

1. liquidファイルの入り
2. gitリポジトリへのhosts設定
3. javaパッケージのインストール
4. embulk binのダウンロード
5. embulkプラグインのインストール

特段面白い事をやってるわけではなくすんなり一通りの手作業をAnsibleに置き換えれましたが、
嵌ったポイントもありました。
> . embulkプラグインのインストール

の中で`embulk gem`を使ってインストールしている部分があるのですが、
playbookでgemのexcutableを指定してやると、


```yaml:main.yaml
    - name: Install embulk's plugins
      gem:
        executable: /home/hoge/embulk gem
        name:   "{{ item.name }}"
        version: "{{ item.versions }}"
        state:  present
        user_install: no
      with_items:
          - { name: 'embulk-decoder-commons-compress', versions: '0.4.1' }
```



```shell:result
TASK [Install embulk's plugins] *************************************************************************************************************************************************************************************************************
failed: [embulk03] (item={u'name': u'embulk-decoder-commons-compress', u'versions': u'0.4.1'}) => {"cmd": "/home/hoge/.embulk/bin/embulk gem query -n '^embulk-decoder-commons-compress$'", "failed": true, "item": {"name": "embulk-decoder-commons-compress", "versions": "0.4.1"}, "msg": "[Errno 8] 実行形式エラー", "rc": 8}
```

と、実行形式エラーとなってしまいました。
どう弄っても回避できなかった（恐らくexecutableにスペースが入る関係で上手くいかない？）ので、
シェルスクリプトを噛ませる事で対処しました。

```shell:embulk_gem.j2
#!/bin/bash
/home/hoge/.embulk/bin/embulk gem $@
```

```yaml:main.yml
    - name: embulk gem wrapper script
      template: src=embulk_gem.j2 dest=/home/hoge/embulk_gem owner=hoge group=hoge mode=777

    - name: Install embulk's plugins
      gem:
        executable: /home/hoge/embulk_gem
        name:   "{{ item.name }}"
        version: "{{ item.versions }}"
        state:  present
        user_install: no
      with_items:
          - { name: 'embulk-decoder-commons-compress', versions: '0.4.1' }
```

この辺りAnsibleのexecutableで解決させたかったのですが、ウマイ方法を募集中

#そんなこんなで総評
この1か月ほどで割と一般的な方法でサーバ構築を自動で行う事ができるところを終わらせる事ができました。
次段階としてインフラCIの整備・コンテナ化に向けた検証を始めていますが、
自動化を行っていく中でも基本的ではありますが新たな気づきがあり、

- 孤独な自動化製作者にならぬよう誰でも扱いやすい形を意識してシンプルなコード化。(KISS原則)
- 単純にコード化するだけでは無く、コード化するサービスの本質を理解する。
- Infra構成コード化作業の習慣作り。

といった事を意識していく事が大事だと感じました。
多分ガチガチにやってる所からすればまだこんなの！？と思われるかもしれないですが、
まずは出来るところからやって行くのが大事と思い現在も自動化の取り組みを継続しています。

最後にアイスタイルでは自動化に興味があるインフラエンジニアを[募集](https://hrmos.co/pages/944062236014428161/jobs/0100004)しています。
一緒にイケてる自動化をやって行きたい！って方がいれば応募をお待ちしております。

明日のAdvent Calendarは@tsukamototaさんです！ご期待ください！