Chef-Soloから卒業、chefのlocalmodeをつかってみた

こんにちは。小宮です。

事の経緯

お急ぎの場合は飛ばして大丈夫です。 Chef-Soloがdeprecated(非推奨)とかで開発元からchef-zero(localmode)をつかうよう周知されたのが半年くらい前でしょうか。 当時はどうしたらええんやと色々比較してみたりしたあげく時が経ってとうとう検証することに。 数年で入れ替わるのではなく長く続くことが前提だとコストをかけても技術的負債を残したくない事情があるケースもあるようで。 個人的には正直コストをかけて移行するかどうかは微妙なところで、soloがすぐ無くなるみたいな話ではない気がしてます。 世の中的にはcookpadさんからitamaeとか出てたりAnsibleが流行ったりなど。 Ansibleはnot_ifに相当する機能を持たせようとするとドライランできなくなるみたいなのが致命的らしいと聞いたけど、 そもそもYAMLに書きなおすコストがあり得ないので試してないです。 itamaeも気になってたんですがroleとenvironmentをattributeになおす手間がありそうでした。 roleもenvironment数もそれなりの規模で配列attributeを優先順位で意図的にdeepmergeしたり初期化するようなことをしてるし その修正はだいぶヘビーな気が。あとdata_bags機能がないのも超困る。他に移行するにはchefの沼にだいぶつかりこんでいたようです。。 あとChef-Serverはコミュニティ版はHA機能がNGだときいたりしました。

現実的にはlocalmodeだろうということでそんな感じでいつもどおり右往左往で検証してみましたので備忘録です。

chefって情報は結構あるんだけどモヒカンの人(技術レベルの高すぎる人)ばっかりなため初心者がどこで惑うか想像つかないのか肝心なところが分かりづらくて 結局念入りにヘルプを眺めたりググりまくって試しまくるなどというのが多いような。。 使い方も多くてそれぞれの環境が違って色々まざると発狂ちょっとこんがらがりやすいかもしれません。

後日、分かりやすい素敵なチャートをみかけたので追記しておきます。 あなたに合ったChefはどれ? 〜 おすすめ構成確認チャート #getchef - クリエーションライン株式会社

普及と発展には分かりやすさというのはとても重要かなと思います。こんな感じのやってみた記事が多少それに寄与するといいなーと思います。

参考情報

まあ色々みてみたんで参考情報からご紹介いたしましょう。パターン分けておきます。 Chef-Zeroの仕組みとか機能とかの話は別途ググっていただくと分かりやすいと思うんですが、、 インメモリChef-Serverローカルモードの違いがありまして、私がやりたいのはローカルモードのほうです。 インメモリChef-Serverとして使う場合は Chef-Zeroを起動してcookbookとroleとenvironmentとdata_bagsのデータなんかをknifeコマンドで登録しておく必要があるようです。 インメモリなので、Chef-Zeroを停止すると登録したデータは消えます。 なので手間を考えるとChef-Serverへの移行を見据えて1次的にとかchef-shellでとれる情報をみたい時に使うという用途になるのかなーと思いました。 ブラウザからアクセスすると登録したjson情報などが見えるのはまあ便利と言えば便利かもしれないけどgitでみればいいやんというレベルだったかなあ。 ローカルモードとして使う場合は、コマンド実行時だけChef-Zeroが内部的に起動してレシピ適用終わったら落ちるようで、 knife.rbに書いといたChef-Repoのパスを勝手に見てくれて余計な手間はなさそうでした。

・Chef-ZeroをインメモリChef-Serverとして動かしたいタイプ Amazon Linuxで簡易Chef Server(chef-zero)を動かしてみた | Developers.IO CentOSにchef-zeroのインストール - clavierの日記 chef-zero を構築して knife-xenserver と連携してみた一部始終 - ようへいの日々精進 XP Ruby - knife zero bootstrap で リモートに chef がインストールできない - Qiita 軽量簡易Chef Server「chef-zero」を使ってみよう #opschef_ja « CREATIONLINE, INC. 【#Docker】Chef Zero を軽量インメモリ Chef Server として使い、ホスト OS から Docker コンテナを Chef で管理する #Chef #GetChef_ja - Qiita

・Chef-Zeroをローカルモードで動かしたいタイプ Chef-Zero & Local Mode Chefのローカルモードだけでリモートサーバを運用してみようと、Knife-Zeroを作った。Nodeの構成情報もとれるよ。 - Qiita サーバー管理者のためのChef超入門(2):Knife-ZeroでCookbookの作成/実行/削除&git cloneコマンドでCookbookの取得 (1/2) - @IT chef_localmode_tutorial/knife.rb at master · higanworks/chef_localmode_tutorial 構成管理ツールChefを使ってみよう - ConoHa VPS(仮想専用サーバー) サーバー管理者のためのChef超入門(2) - @IT の補足、Cookbookのディレクトリ - Qiita Knife-Zero bootstrapを用いてAmazon EC2にChefをインストールする際の手順 - Qiita Chef-SoloからChef-Clientローカルモードへの移行 #opschef_ja #getchef_ja « CREATIONLINE, INC. oreno knife-zeroメモ - orenoblog

・その他 DevOpsを実現する為のChef実践テクニック Chef12対応版 Chef を始める #1 – 概要、Chef Server を EC2 上にインストール、Workstation の設定まで | Developers.IO #GetChef_ja - Twitter検索 knifeコマンドが面倒すぎるので「knife-helper」というpluginを作った #getchef_ja - Miscellaneous notes knifeコマンドが面倒すぎるので「knife-helper」というpluginを作ったのでチュートリアル(knife-zero,knife-ec2で) - Qiita knife.rb — Chef Docs GNU parallelを試してみた | Ore no homepage

あと「chef活用ガイド」を念入りにみる。チュートリアルが無い辞書みたいですが、日本語でmanが読めてラッキー♪と最近やっと思いました。

Chef-Zero,Knife-Zeroのインストール

OSはCentOS6.5です。 とりあえずrubyのバージョンが低いとohaiに怒られる感じでしたので検証環境にはrbenvで2.1.5を入れてグローバルにしておきました。 (ただちょっとDLの警告がでとります。。) chef-dkとかもあるが入るパスが気になるのでとりあえずgemで入れてみました

bundlerつかうほうが依存関係が管理できるので以下はしない $ sudo -i gem install chef-zero json –no-ri –no-rdoc $ sudo -i gem install knife-zero –no-ri –no-rdoc

bundleの前にスイッチユーザでrootになる

$ sudo su -
# cd /path_to_chef-repo/
# vi Gemfile

source 'https://rubygems.org'

gem 'berkshelf', '~>3.0.0'
# berkshelf require hashie/hash_extensions file.
gem 'hashie', '>=2.0.2', '<3.0.0' gem 'chef' #追加 gem 'chef-zero' #追加 gem 'knife-zero' #追加 group :test do gem 'foodcritic', '~>3.0.0'
gem 'test-kitchen', '~>1.3.0'
gem 'mixlib-shellout', '~>1.3.0'
gem 'kitchen-ec2', '~>0.8.0'
gem 'serverspec'
end

# bundle install
Successfully installed net-ssh-2.9.3.beta1
Successfully installed net-scp-1.2.1
~略~
Successfully installed mixlib-authentication-1.3.0
Successfully installed chef-12.2.1 ※※chef12が入る
Successfully installed knife-zero-1.4.0
34 gems installed

一覧表示
# bundle show

chef-clientについては以下の入れ方もあって sudo curl -L https://www.opscode.com/chef/install.sh | bash -x これをすると、workstationではchef-12.2.1-1.el6.x86_64.rpm を入れようとしてくれる。(2015/4時点) knife-zeroを入れるとchef-12も勝手に入ってとりあえずそれでも動くことは動きそう。 ただしリモート側にknife zero bootstrapで入れるとrubyバージョンに寄るのか chef (11.12.4) chef-zero (2.0.2) が入る。レシピ適用は可能。

helpは$ knife help listとするとみられるものが一覧できる。knife zero bootstrap --helpとするとknife zero用のhelpもみられるはず。 みられなかったらたぶん上手く入ってない。

Chef-Clientのローカルモードでレシピをローカルホストに適用する

IAMロールとcloud-init的なもんをつかってAMIから起動した瞬間にローカルホストにレシピあてたい場合には たぶん特にchef-zero立てるという必要はなさそうで、Chef-Repoをgit cloneしてきて鍵取得してパラメータ渡して以下のようなのが実行されればよさそう。

$ sudo chef-client -z -r role[web] -E sandbox --validation_key /etc/chef/validation.pem

-zつけるとchef-zeroがその時だけ走る仕様になっているようで、既にchef-zeroが起動しててポートが競合してるとエラー終了になる感じでした。 オプションの詳細はコマンドに–helpつけるとみられます。optionはclient.rbに書いてあれば指定しなくても大丈夫。 git cloneとかでchefリポジトリ落としてきたあとにこんなかんじでOKぽい。sudoつけないと権限が必要な処理のとこでエラー終了でした。 knife.rbとclient.rbとvaridation-key的なもんの設定は必要ですけども。(chefリポジトリの改修は要らなかった!yes!!) 実はchef-zeroが入ってなくてもchef-clientはローカルモードオプション付きで動いてレシピ適用は可能なようでした。 (INFOでchef-zeroサーバがNotFoundとか出るし内部的にコマンド実行時のみ起動して終わった後落ちるみたいなのがないけどレシピは流れる)

chef-repo/.chef/knife.rbは以下のようにしてみました。localmode true入れとけば-zつけなくてもローカルモードで動くようでした。

chef_repo = File.join(File.dirname(__FILE__), "..")
current_dir = File.dirname(__FILE__)
log_level :info
log_location STDOUT
#node_name `uname -n`
client_key "#{current_dir}/dummy.pem"
validation_client_name 'chef-validator'
validation_key "#{current_dir}/dummy.pem"
#validation_key "/etc/chef/validation.pem"

cookbook_path ["#{chef_repo}/cookbooks", "#{chef_repo}/site-cookbooks"]
node_path "#{chef_repo}/nodes"
role_path "#{chef_repo}/roles"
environment_path "#{chef_repo}/environments"
data_bag_path "#{chef_repo}/data_bags"
encrypted_data_bag_secret "path_to_databagkey"
knife[:berkshelf_path] = "#{chef_repo}/cookbooks"
#knife[:ssh_user] = ""
#knife[:ssh_password] = ""
knife[:ssh_port] = 22
knife[:editor] = "vim"
localmode true

chef_server_url 'http://127.0.0.1:8889'
syntax_check_cache_path "#{current_dir}/syntax_check_cache"

#puts Chef::Config.inspect

chefの設定ファイルはrubyっぽいことがなんとなくわかってきました。(今更 node_nameにバッククォートで渡してみたところknife zero bootstrapはいけるんですが、chef-clientが動かなくなるようでした。 鍵は以下の手順で準備してみました。chef-zeroは認証が不要らしいですが、形式的に鍵が必要らしく無いとknifeが実行できずにエラー出ます。

$ ssh-keygen -t rsa -N "" -f ~/chef-repo/.chef/dummy.pem

/etc/chef/client.rbは以下のように。書けるパラメータは「Chef活用ガイド」に載ってました。

log_level :info
log_location STDOUT
chef_server_url "https://127.0.0.1:8889" ## Chef-ZeroのAPIエンドポイント
#validation_client_name 'chef-validator'
client_fork true
client_registration_retries 5
#node_name `uname -n`

#puts Chef::Config.inspect

workstationからリモートのclientにレシピを適用したい場合

紆余曲折の後、以下のような感じでknife zeroを用いて上手くいきました。

url=https://www.opscode.com/chef/install.sh
newip=xxx.xxx.xxx.xxx
role=web
env=sandbox
user=hoge
dpas=`cat /pashto_sshpassword_file`
$ knife zero bootstrap --node-name $newip --bootstrap-url $url -i .chef/dummy.pem -x $user --sudo \
-E $env -r role\[rolename\] -z -s $(cat ./databag_key) -P $dpas $newip

bootstrapだけどレシピ適用までコマンド一発で終わっていました。 ログインしてみてみると、/etc/chef/client.rbなどが自動的に作られていてdata_bags用の鍵がコピーされて置かれていました。次回以降に-sは不要でした。 (リポジトリはどこにもなくてrsyncの負荷がかぶるとworkstationの複数実行してる処理が片方落ちるみたいなんは無さそうだなと思いました。 さわのぼりさんが2000ノードまでいけるとか検証した記事を見かけた気がしますがマシンスペックがかいてないなあと思った記憶はあります。)

$ ls /etc/chef
client.pem client.rb encrypted_data_bag_secret first-boot.json validation.pem

$ sudo cat /etc/chef/client.rb
log_location STDOUT
chef_server_url "http://localhost:8889"
validation_client_name "chef-validator"
node_name "10.xxx.xxx.xxx"

というわけでめでたしめでたし。 ちょっと鍵認証したいのにパスワード認証になっちゃうのが納得いかねえ!と思うのですがまだなんともなってないです。 結構詰みやすいところかもしれない。ポートフォワーディングに慣れてないからなのかな。よくわかんないです。 knife.rbに平文で書くのは書けるのでコミットしないように注意して運用する感じでしょうか。 #knife[:ssh_user] = "" #knife[:ssh_password] = ""

knife zeroのサブコマンドはあと2つあって、clientとdiagnoseらしいです。 clientは2回目以降のレシピ適用に使う感じでdiagnoseは設定見に行ってくれるようです。

・clientは以下のようにしたところ動きました。-oで部分的にレシピを適用する例です。

$ knife zero chef_client -c ~/chef-repo/.chef/knife.rb 'name:10.xxx.xxx.xxx' \
-x $user -i .chef/dummy.pem --sudo -E $env -o base::openssl -a ipaddress 10.xxx.xxx.xxx --remote-chef-zero-port 8889 -z

・diagnoseは以下のように現在認識されてる値が一覧表示される感じですね。 コマンドが動かないときに確認すると足りない設定やオプションがないか分かってよさそうです。

$ knife zero diagnose -c ~/Chef-Repo/.chef/knife.rb -z
Chef::Config
====================
---
:local_mode: true
:knife_zero: true
:verbosity:
:config_file: "/path-to-config/.chef/knife.rb"
:log_level: :error
:log_location: !ruby/object:IO {}
:node_name: |
~略~

「knife zero bootstrap ≒ knife solo prepare+cook」, 「knife zero chef_client ≒ knife ssh+search+cook」,という様な認識でいます。 ここまでknife zeroつかっといてなんですが、knife soloもローカルモードに対応する予定はありそうです。 (BlueGreenデプロイ的な挿げ替える運用で結構動的にnode構成が変わるから管理したくないという場合にはknife zeroだと手に余りそうというか。) Chef-Solo, Chef-Client LocalMode, Knife-Solo, Knife-Zero and us. — sawanoboly.net add local_mode to solo.rb · Issue #353 · matschaffer/knife-solo (関連ディレクトリをまるまる転送、リモートでLocalMode相当の実行形式に変更など)

knife-zero面倒なら、knife-solo相当の処理をローカルモードで自分で頑張るというのでもいいかと。 つまりChef-Repo転送しといてssh越しにchef-clientたたくのもいいと思います。(sudoするならsshに-tつけるといいです)

並列処理について

CPUが1コアだからか並列さを感じられなかったんですが、以下のようなGNUのparallelというコマンドを用いることで動きました。 標準出力は完了してから1台ずつ一気にくる感じでした。出力がホスト毎に混ざるようなことはなかったです。

$ parallel -j 3 knife zero bootstrap -c ~/Chef-Repo/.chef/knife.rb -z -E $env -r role\[role-name\] \
-i .chef/dummy.pem -s $(cat ~/path_to_databag-key) --sudo --no-host-key-verify ::: $host1 $host2

parallelのmanみたところファイルから食わせるとかもできそうでした。 knifeのhelpみてエラーに悩まされるよりは楽なのかもしれません。ただrpmがないのでmakeするかrpm自作するかして入れる必要があります

Search機能を使ってみた

・data_bagsのなかみを検索する例

$ knife show data_bags/base/* --local-mode
$ knife search nginx 'id:nginx_status' --local-mode
$ knife search nginx 'servername:"proxy01"' --local-mode
$ knife search nginx 'servername:"*.net"' --local-mode --id-only
$ knife search nginx 'servername:*.net AND certificatename:xxx-wildcard' --local-mode

--id-onlyを付けるとidだけでてきます。ANDの他にORとNOTも使えるようです。 次の特殊文字はバックスラッシュ付けないとだめみたいです(Chef活用ガイドP242あたりより) + - && || ! () {} [] ^ " ~ * ? : \

searchした結果を並列実行とかできたら嬉しいけどnodeの管理をちゃんとやらないといけなくなるかなと思いました。

では、ちょっと長くなったのでこの辺で失礼します。 みていただいてありがとうございました。