OpsWorks customize.rbでbuilt-in cookbooksの設定値を変更する



[OpsWorks](http://aws.amazon.com/jp/opsworks/)でRailsアプリを運用していますが、ファイルのアップロードに対応するにあたり、nginxの設定を変更する必要がありました。

カスタムJSONは、設定をバージョン管理に含められないので管理がし辛いためあまり好きでなかったのですが、調べてみると Custom Cookbooks のリポジトリ内に customize.rbというファイルを置くことで、nginxをはじめとするbuilt-in cookbooksの設定ができることがわかりました。

[【AWS発表】AWS OpsWorks が Chef 11.10 をサポート](http://aws.typepad.com/aws_japan/2014/03/aws-opsworks-now-supports-chef-1110.html)

> Chefに含まれるRubyのバージョンもアップデートされています。また、ビルトインクックブックのための非常に便利なカスタマイズ機能を用意しました。クックブックのattributesディレクトリにcustomize.rbファイルを置くだけで、OpsWorksがインストールするソフトウェアの設定を変更することができます。

[Overriding AWS OpsWorks Attributes Using Custom Cookbook Attributes](http://docs.aws.amazon.com/opsworks/latest/userguide/workingcookbook-cookbook-attributes.html)

> Custom JSON is a convenient way to override AWS OpsWorks stack configuration and built-in cookbook attributes, but it has some limitations. In particular, you must enter custom JSON manually for each use, so you have no robust way to manage the definitions. A better approach is often to use custom cookbook attribute files to override built-in attributes. Doing so allows you to place the definitions under source control.

**この方法なら、カスタマイズ内容もバージョン管理に含めることができ、設定漏れなどのリスクを減らすことができそう**です。


## 実現したいこと

- **ビルトインクックブックの挙動を変更する**
  - nginx 
     - `client_max_body_size`
     - `proxy_send_timeout`
- **バージョン管理可能にする**
  - カスタムJSONを使用しない
- 元レシピをForkするなどアップデート対応が面倒なことはしない


## 手順

1. 対象のクックブックの内容を確認
2. Custom Chef Cookbooksのリポジトリを作成
3. customize.rbを配置
4. StackにCustom Chef Cookbooksのリポジトリ登録・更新
5. Update Custom Cookbooks
6. レシピ実行

## 1. 対象のクックブックの内容を確認

**[Chef Cookbooks for the AWS OpsWorks Service](https://github.com/aws/opsworks-cookbooks)**から目的のレシピを読んで設定値を確認します。

[nginxならこのへん。](https://github.com/aws/opsworks-cookbooks/blob/release-chef-11.10/nginx/attributes/nginx.rb)

    # increase if you accept large uploads
    default[:nginx][:client_max_body_size] = "4m"
 
    default[:nginx][:proxy_read_timeout] = 60


## 2. Custom Chef Cookbooksのリポジトリを作成

Custom Chef Cookbooksは各インスタンスのsite-cookbooksに展開されます。

リポジトリ内にsite-cookbooksを作成するのではないことに注意して下さい。

    $ mkdir site-cookbooks
    $ git init
    $ touch README.md
    $ git add .
    $ git commit -m 'first commit'
    $ git remote add origin https://github.com/xxxxxx/myproject-cookboooks.git
    $ git push origin master

当然ですがすでにプロジェクトでCustom Chef Cookbooksを使用しているのであれば、それを使えば良いので新たに作成する必要はありません。

## 3. customize.rbを配置

Custom Chef Cookbooksリポジトリ内にcustomize.rbを配置します。

場所は、`カスタマイズしたいCookbook名/attributes/customize.rb`です。

丁度対象のクックブックにサンプルのcustomize.rbが用意されているので、これをコピーして同じように配置すればよいと思います。
**その他のレシピや設定（nginx.rbとか）等は不要**です。

`nginx/attributes/customize.rb`

    ###
    # This is the place to override the nginx cookbook's default attributes.
    #
    # Do not edit THIS file directly. Instead, create
    # "nginx/attributes/customize.rb" in your cookbook repository and
    # put the overrides in YOUR customize.rb file.
    ###
    
    # The following shows how to disable NGinx compression:
    #
    #normal[:nginx][:gzip] = 'off'
    #normal[:nginx][:gzip_static] = 'off'
    
    # for Upload
    normal[:nginx][:client_max_body_size] = "10m"
    normal[:nginx][:proxy_send_timeout] = "300"

ここでは`client_max_body_size`を10MB、 `proxy_send_timeout`を300秒に設定しました。

完成したらpushしておきます。

なお、今僕が進めているプロジェクトのものはこんな感じの配置になっています。

![custom chef cookbooks](http://i.imgur.com/tZ3E7ir.png)


## 4. StackにCustom Chef Cookbooksのリポジトリ登録

スタックの設定を開き、**User custom Chef Cookbooks**に、作成したCookbooksリポジトリを指定します。

![Edit Stack](http://i.imgur.com/IzDG1Yn.png)

なお、GitHubのプライベートリポジトリを使用している場合、SSHを使いますが、普通に22番ポートで接続しようとするとうまくいかないことが多いので

`ssh://git@ssh.github.com:443/xxxxxx/myproject-cookboooks.git`

のようにSSLのポートを使用します。

## 5. Update Custom Cookbooks

設定するだけでは反映されないので、スタックの`Run Command`より、**Update Custom Cookbooks**を実行します。

![Update Custom Cookbooks](http://i.imgur.com/rt60Es0.png)

これにより、各インスタンスの`/opt/aws/opsworks/current/site-cookbooks`に作成したレシピが配置されます。

## 6. レシピ実行

nginxのレシピはRails App Serverであれば通常のデプロイ時に実行されるはずですが、ここでは手動で実行してみます。

スタックの`Run COmmand`より**Execute Recipes**を選択し、**Recipes to execute**でnginxの設定ファイルを更新するレシピを選択します。

    nginx::stop,nginx::default

ここではnginxをいったん停止し、設定ファイルを更新、起動するという指定をしてみました。現実には、自分でreloadとか用意した方がいいかもしれません。

**Execute Recipes**ボタンを押すと、レシピの実行が成功し、nginxの設定ファイルも更新されています。

![Run result](http://i.imgur.com/tqYU5cw.png)

生成された設定ファイル（`/etc/nginx/nginx.conf`）

    user nginx;
    worker_processes  10;
    
    error_log  /var/log/nginx/error.log;
    pid        /var/run/nginx.pid;
    
    events {
      worker_connections  1024;
    }
    
    http {
      include       /etc/nginx/mime.types;
      default_type  application/octet-stream;
    
    
      access_log    /var/log/nginx/access.log;
    
      sendfile on;
      tcp_nopush on;
      tcp_nodelay on;
    
      keepalive_timeout  65;
    
      gzip  on;
      gzip_static  on;
      gzip_http_version 1.0;
      gzip_comp_level 2;
      gzip_proxied any;
      gzip_types application/x-javascript application/xhtml+xml application/xml application/xml+rss text/css text/javascript text/plain text/xml;
      gzip_vary on;
      gzip_disable "MSIE [1-6].(?!.*SV1)";
    
      client_max_body_size 11m;
    
      server_names_hash_bucket_size 64;
    
      include /etc/nginx/conf.d/*.conf;
      include /etc/nginx/sites-enabled/*;
    }


実行ログ
    
    [2014-10-13T00:51:12+00:00] INFO: Processing service[nginx] action nothing (nginx::service line 1)
    [2014-10-13T00:51:12+00:00] INFO: Processing service[nginx] action stop (nginx::stop line 3)
    [2014-10-13T00:51:13+00:00] INFO: service[nginx] stopped
    [2014-10-13T00:51:13+00:00] INFO: Processing package[nginx] action install (nginx::default line 21)
    [2014-10-13T00:51:17+00:00] INFO: Processing directory[/etc/nginx] action create (nginx::default line 23)
    [2014-10-13T00:51:17+00:00] INFO: Processing directory[/var/log/nginx] action create (nginx::default line 29)
    [2014-10-13T00:51:17+00:00] INFO: Processing directory[/etc/nginx/sites-available] action create (nginx::default line 36)
    [2014-10-13T00:51:17+00:00] INFO: Processing directory[/etc/nginx/sites-enabled] action create (nginx::default line 36)
    [2014-10-13T00:51:17+00:00] INFO: Processing directory[/etc/nginx/conf.d] action create (nginx::default line 36)
    [2014-10-13T00:51:17+00:00] INFO: Processing template[/usr/sbin/nxensite] action create (nginx::default line 44)
    [2014-10-13T00:51:17+00:00] INFO: Processing template[/usr/sbin/nxdissite] action create (nginx::default line 44)
    [2014-10-13T00:51:17+00:00] INFO: Processing template[nginx.conf] action create (nginx::default line 52)
    [2014-10-13T00:51:17+00:00] INFO: template[nginx.conf] backed up to /root/.chef/local-mode-cache/backup/etc/nginx/nginx.conf.chef-20141013005117.675539
    [2014-10-13T00:51:17+00:00] INFO: template[nginx.conf] updated file contents /etc/nginx/nginx.conf
    [2014-10-13T00:51:17+00:00] INFO: Processing template[/etc/nginx/sites-available/default] action create (nginx::default line 60)
    [2014-10-13T00:51:17+00:00] INFO: Processing service[nginx] action enable (nginx::default line 69)
    [2014-10-13T00:51:18+00:00] INFO: Processing service[nginx] action start (nginx::default line 69)
    [2014-10-13T00:51:18+00:00] INFO: service[nginx] started