Devlog

A developer day.

Chef-solo 「Data Bag Items Must Contain a Hash or Mash!」

Chef-solo の 「Data Bag」の記述で少し嵌ったのでその対処法について。

結論から言うと、ドキュメントをよく読めということでした。

環境構成

OS: Amazon Linux AMI 2013.03
Chef-solo: 11.4.0
knife-solo: 0.2.0

やりたかったこと

templateを利用して、nginx.confの「upstream」ディレクティブに複数サーバーホストを設定する。

開発環境と本番環境でサーバー台数が違うし、サーバーの増減で都度テンプレートを触りたくなかったので、「Data Bag」という仕組みを利用する

Data Bagの使い方がこれで合っているか不明ですが、現在のところサーバー情報をdata_bagsで管理しています。

data_bags 設定

下記のように、 [webapservers] というdata_bagを作成し、その中に環境毎のサーバー情報を管理する [development] [production] というdata_bag_itemを作成します。

1
2
3
4
5
$ tree data_bags
data_bags
└── webapservers
    ├── development.json
    └── production.json

knife solo cook ~ を実行した際に、下記のようなエラーが発生しました。

1
2
3
Chef::Exceptions::ValidationFailed
----------------------------------
Data Bag Items must contain a Hash or Mash!

data_bag_item の記述の仕方が間違っていることが原因でした。

間違いな例:

data_bags/webapservers/development.json

1
2
3
4
5
6
7
8
9
10
11
12
{
    "servers":[
        {
            "ip" : "10.0.58.131",
            "port" : "8080"
        },
        {
            "ip" : "10.0.58.132",
            "port" : "8080"
        }
    ]
}

正しい例:

data_bags/webapservers/development.json

1
2
3
4
5
6
7
8
9
10
11
12
13
{
    "id" : "development",
    "servers":[
        {
            "ip" : "10.0.58.131",
            "port" : "8080"
        },
        {
            "ip" : "10.0.58.132",
            "port" : "8080"
        }
    ]
}

data_bag_itemには「 id:」 が必須でした。

ドキュメントにもちゃんと記載されていました。

chef-data-bag

recipes 設定

レシピは下記のようにdata_bagからサーバー情報を取得して、templateリソースの variables を使用して “proxy_elb.conf.erb” にサーバー情報を渡しています。

site-cookbooks/nginx/recipes/default.rb

1
2
3
4
5
6
7
8
9
10
servers = data_bag_item('webapservers','development')['servers']

template "/etc/nginx/nginx.conf" do
    source "proxy_elb.conf.erb"
    owner "root"
    group "root"
    mode 0644
    notifies :reload, 'service[nginx]'
    variables :webapservers => servers
end

templates 設定

テンプレートでは下記のように値を取得して、upstreamディレクティブの設定を行なっています。

site-cookbooks/nginx/templates/default/proxy_elb.conf.erb

1
2
3
4
5
6
upstream backend {
    #ip_hash;
    <% for server in @webapservers %>
        server <%= server["ip"] %>:<%= server["port"]%>;
    <% end %>
}

以上。

Comments