fbpx

[和訳] 初心者Chefアンチパターン by Julian Dunn #opschef_ja

この記事は1年以上前に投稿されました。情報が古い可能性がありますので、ご注意ください。

本項はChefConf 2013: Beginner Chef Antipatternsを和訳したものです。

はじめに

よく

  • Chefの学習は大変
  • Chefの学習曲線は急勾配

と言われているので、Opscodeでは緩和するためのコンテンツを色々準備しています。

それでも、正しいことをやっているのか知るのは難しく、何か間違ったことをやっているのか知るのはさらに難しいものです。コミュニティの中で「ベストプラクティス」は常に進化してきました。

ベストプラクティスについてもっと知りたかったのに...。
インストラクターはよくある落とし穴を説明するのに、脱線せずにはいられなかった。

- Chef基礎トレーニングのフィードバックより

本項では、優れた板前(Chef)に早くなるためのベストプラクティスを紹介します。

あらかじめ計画を立てる

まずはじめに、「よく練られた計画に勝るものはない」ということを挙げます。

  • 必要なCookbookはどのようなものか?
  • どのようなRecipeか?
  • Roleとそれらの名前は?
  • Environmentはいくつか?
  • それらのEnvironmentに所属するクラスタは?
  • Data Bagの階層と名前、Data Bag Itemの構造

そして、10のアンチパターンがあります。

10. すべてのChefデータを1つの巨大なGitレポジトリに入れてしまう


git://github.com/yourcompany/chef-repo.git

なぜこれが悪いのでしょうか?

  • environmentsやrolesといった一時的なデータがcookbooksのようなヴァージョン管理されたデータと混ざってしまう
  • Gitの哲学: 個々にヴァージョン管理されているものは個々のGitレポジトリにする
  • 多くのGitレポジトリを持つことを恐れない!

次のようにしましょう:


git://github.com/yourcompany-cookbooks/foo.git

より合理的には次のようにしましょう:


git remote add upstream git://github.com/whatevs/upstream.git
git fetch upstream
git merge upstream/master

ちょっとACLをいじるだけで、簡単に改良したCookbookをオープンソースにもできます。

9. 会社名つきの巨大なCookbookを作ってしまう


git://github.com/yourcompany-cookbooks/yourco.git

なぜこれが悪いのでしょうか?

  • Cookbookは上位レベルのサービスを設定するもの
  • 巨大なCookbookは一緒にしてはいけない・組み合わせてはいけないものを混ぜてしまう
  • Recipeに対する変更の影響範囲が非常に大きくなり、障害の原因となる

次のようにするより:

+ cookbooks
  + yourcompany
    + recipes
      |
      +- mainsite-apache-virtualhost.rb
      +- anothersite-apache-virtualhost.rb
      +- spring-properties.rb

次のようにしましょう:

+ cookbooks
  + mainsite
  | + recipes
  |   +- apache-virtualhost.rb
  |
  + anothersite
  | + recipes
  |   +- apache-virtualhost.rb
  |
  + springproperties
    + recipes
      +- properties.rb

8. "Environments"を単なる論理的な「環境」以上の目的で使ってしまう

  • Environmentsは実際の「環境」に対応づけるための論理的な概念
  • だけど、Environmentsを「クラスタ名」や「データセンタ名」として使いたくなるのは過剰なので避ける!

次のようにしてはいけません:


mongos = search(:node, "role:mongodb AND chef_environment:#{node.chef_environment}")

もし「production」Environmentに2つ以上のMongoDBクラスタがあったら正常に動作しない可能性があります。

次のようにしましょう:


node.set['mongodb']['cluster_name'] ='mongocluster1'

mongos = search(:node, "role:mongodb AND chef_environment:#{node.chef_environment} AND mongodb.cluster_name=#{node['mongodb']['cluster_name']}")

次のようにするとさらによいでしょう:


node.set['globals']['data_center'] = 'portlandia'
node.set['mongodb']['cluster_name'] ='mongocluster1'

mongos = search(:node, "role:mongodb AND chef_environment:#{node.chef_environment} AND mongodb.cluster_name=#{node['mongodb']['cluster_name']} AND globals.data_center=#{node['globals']['data_center']}")

7. Community Cookbookをフォークしてしまう

  • Opscodeは130以上のCookbookを管理しています
  • Opscode以外でもRedisやMongoDBといったよく管理されたすばらしいものがあります
  • このようなCookbookをフォークする誘惑に抵抗すること!
  • フォークしたら、開発元のバグ修正や機能追加といった恩恵を受け取れなくなります
  • フォークするより、独自の変更点をかぶせるように、アプリケーション/ライブラリCookbookを利用しましょう
  • 例として、SecondMarketの「ラッパー」PostgreSQL Cookbookがあります。参考: smpostgresql/recipes/server.rb

6. Role内でrun_listを管理してしまう

  • これには議論の余地があります!
  • Opscodeのトレーニングでは、run_listをRoleに入れるように言っています
  • しかし……Roleはヴァージョン管理できない、一時データです
  • Role内にあるrun_listを複数の環境にまたがって変更するには、少し危険な作業になってしまいます

次のようにする代わりに:


"run_list": [
"recipe[selinux::permissive]",
"recipe[rsyslog]",
"recipe[chef-client::config]",
"recipe[chef-client::service]",
"recipe[chef-client::delete_validation]",
"recipe[openssh::iptables]"
]

次のようにしましょう:


% knife cookbook create roles
% vi roles/base.rb

"run_list": [ "recipe[roles::base]" ]

roles/recipes/base.rb:


include_recipe "selinux::permissive"
include_recipe "rsyslog"
include_recipe "chef-client::config"
include_recipe "chef-client::service"
include_recipe "chef-client::delete_validation"
include_recipe "openssh::iptables"

  • 必要なら、条件分岐も含めましょう
  • または、Role AttributesをRecipeに含めましょう

5. 無秩序なdata bagを作ってしまう

  • Data Bag と Data Bag Item という2階層しかないので、よく計画すること!
  • Data Bag Item を巨大な JSON ハッシュにしないこと
    • パフォーマンスのためには小さくなるようにしておきましょう
  • 8 KB JSON x 4 Chef runs/h x 1000 nodes = 5.38GB/week!

4. chef-shellを知らない、使わない

  • Chef-Shell (旧 Shef)は全然活用されてないツールのひとつ!
  • irb (インタラクティブRuby)にChefの根源的な要素を足したようなもの
  • Cookbook開発に適しています
  • 製品のデバッグにも使えます

次のようなテンプレートがあるとします:


29: <% @members.each do |member| -%>
30: <%= member['hostname'] %> IN CNAME <%= member['ec2']['public_hostname'] %>.
31: <% end -%>

Chef-Shell でテストしてみます:


[jdunn@dns1 ~]$ chef-shell -z
loading configuration: /etc/chef/client.rb
Session type: client
.
.
chef > echo off
chef > members = search(node, "domain:epicfail.com")
chef > members.each do |m|
chef > pp "#{m['hostname']}, #{m['ec2']['public_hostname']}"
chef ?> end
"host1, ec2-50-17-43-13.compute-1.amazonaws.com"
"host37, ec2-23-23-145-243.compute-1.amazonaws.com"
"host3, "

NoMethodError: undefined method `[] for nil:NilClass

このように、商用環境に適用する前に問題あることが発見できました。

3. LWRPを怖がってしまう

神話: LWRPを書くのは大変! Rubyを覚えなきゃいけないし!

  • インラインResourcesを使えばいい
  • Array, Hash, String など、基本的なRubyのクラスやメソッドを知っていれば十分
  • LWRPフレームワークは……軽量で、なおかつたくさんのことをしてくれる

例えば、次のようなResourceは:

cookbooks/mouse/recipes/default.rb:


mouse "Itchy" do
says "Ow, Scratchy cut off my tail"
tail false
action :say
end

次のようなResource定義と:

cookbooks/mouse/resources/default.rb:


actions :say

attribute :given_name, :name_attribute => true
attribute :phrase, :default => "squeak"
attribute :tail, :default => true, :kind_of => [TrueClass, FalseClass]

次のようなProvider実装でできます:

cookbooks/mouse/providers/default.rb:


action :say do
log "My name is #{new_resource.given_name}"
log new_resource.phrase unless new_resource.phrase =~ /^squeak$/
log "I #{new_resource.tail ? 'do' : 'do not' } have a tail
end

簡単でしょう?

NIH(Not Invented Here)症候群 (外部発祥だから利用しない症候群) に陥ってしまう

  • 他者のコード/ライブラリ/Cookbookを使うことに対する(悪い)先入観
  • 自分自身があつらえたCookbookを書きたくなる誘惑
  • その代わりに、まず調べましょう。適したものを見つけましょう。そして、それをライブラリ/アプリケーションCookbookの中で使いましょう
  • 改善や変更を寄贈しましょう

1. 孤独なChef使いになってしまう

最大のChefアンチパターンは店でたった一人の板前(Chef)になってしまうことです。

  • 唯一の板前(Chef)がバスやトラックに轢かれたらどうする?
  • 板前(Chef)はアプリケーションを設定します
    • 開発者は板前(Chef)よりもアプリケーションについて知っています
    • 開発者にCookbookを書かせたり管理させましょう
  • そうすれば、みんなが製品に対して責任を持つことになります

おさらい: 10のアンチパターン

  • すべてのChefデータを1つの巨大なGitレポジトリに入れてしまう
  • 会社名つきの巨大なCookbookを作ってしまう
  • "Environments"を単なる論理的な「環境」以上の目的で使ってしまう
  • Community Cookbookをフォークしてしまう
  • Role内でrun_listを管理してしまう
  • 無秩序なdata bagを作ってしまう
  • chef-shellを知らない、使わない
  • LWRPを怖がってしまう
  • NIH症候群 (外部発祥だから利用しない症候群)に陥ってしまう
  • 孤独なChef使いになってしまう

クリエイティブ・コモンズ・ライセンス
初心者Chefアンチパターン by CREATIONLINE,INC. is licensed under a Creative Commons 表示 - 継承 2.5 非移植 License.
ChefConf 2013: Beginner Chef Antipatterns by Julian Dunnに基づいている。

新規CTA