[和訳] Test Kitchen: 開発のフィードバック工場 #getchef
この記事は1年以上前に投稿されました。情報が古い可能性がありますので、ご注意ください。
本稿は Test Kitchen: Your Development Feedback Factory (2015/09/10) の和訳です。
Test Kitchen はさまざまなプラットフォーム上で Cookbook のテストを簡単に行えるようにします。Test Kitchen を使うと、テスト用 Node を素早く作成し、収束し、さまざまな状態を検証するテストを実行することができます。
この webcast の録画では、Chef 社のエンジニア Fletcher Nichol が自信を持って Chef Cookbook を書いてメンテナンスするためにどのように Test Kitchen を使うかの説明をしています。Fletcher は次のことを共有しました:
- どのように Workstation を設定するか
- どのように対象のプラットフォームで動作する新しい Cookbook を作成するか
- どのように新しい OS と Chef Client のリリースを取り扱うか
- どのように Windows の世界で遊ぶか
ライブ中に答える時間がなかった質問を含む Q&A は次の通りです。
ライブ webinar からの Q&A
Q: Test Kitchen は、Cookbook を Chef Server にアップロードして指定の Node で Chef Client を実行することと、開発ワークフローを比較すると、どのように違うのですか? 言い換えると、Test Kitchen の恩恵とは何ですか?
A: Test Kitchen において、できる限り直接かつエラーなしで実行するようなコードの開発を行えるように努めてきました。更新した Cookbook を Chef Server にアップロードし忘れたと気がつく前に、Cookbook の問題をデバッグするのに貴重な時間を何分、何時間も費してきました。ここでの考え方は、エディタ中のコードを保存して kitchen converge … を実行することをできる限り早くすることです。これが第一の利点だと言えるでしょう。
Q: Test Kitchen が Cookbook とその依存関係を Chef Server にアップロードする方法を提供する予定はありますか?
A: 実際の Chef Server に Cookbook をアップロードするには、chef_client Test Kitchen プロビジョナをサポートする必要があります(chef_solo と chef_zero という似たプロビジョナが既にあります)。しかし、あなたのプロジェクトで Berksfile を使っているなら、Test Kitchen はリモートインスタンスに Cookbook をアップロードする前に、本質的に berks vendor --path [TMP_PATH] を実行しています。実際の Chef Server に Cookbook をアップロードして適用する似たようなコマンドを実行可能です。kitchen converge プロセスは Berksfile.lock をとにかく生成しようとするので、berks upload と berks apply [ENVIRONMENT] が動作するはずです。
Q: EC2 ドライバについて質問があります。作成しようとする新しいインスタンスを有効にするのに、Cookbook のどこかに AWS アカウントの Credential を提供する必要がありますか?
A: はい。ドライバ名を「ec2」に変更するとき、あらゆるプロジェクトのためにシステム上で実行するユーザのデフォルト値を提供する $HOME/.kitchen/config.yml というグローバル設定ファイルが Workstation にあります。次のような内容になっています:
---
driver:
name: ec2
region: us-west-2
instance_type: m4.large
iam_profile_name: fnichol-provisioning
aws_ssh_key_id: fnichol-aws-ssh-key
tags:
x-project: test-driven-infrastructure
x-sub-project: feedback-factory
created-by: test-kitchen
transport:
ssh_key: /Users/fnichol/.ssh/id_rsa-aws
これは AMI を取得するのに十分なデフォルト設定を提供し、この webinar での他の credential を無視します。できれば他の空欄を埋める必要があります。他の設定については、設定 Attribute が書かれている kitchen-ec2 README を参照する価値があります。
Q: 単一の .kitchen.yml ファイル内で複数のドライバを指定できますか?
A: もちろんできます! (すべてのプラットフォームとスイートを一緒にして作成された)それぞれ、すべての Test Kitchen インスタンスは、個別の Driver、Provisioner、Verifier などを持っています。興味深い組み合わせは次のようになります:
---
driver:
name: vagrant # すべてのインスタンスのデフォルト
platforms:
- name: ubuntu-15.04
- name: centos-7.1
- name: amazon-2015.03
driver:
name: ec2 # AWS のみで有効
image_id: ami-XXXXX
- name: windows-8.1
driver:
name: hyperv # Windows なら、組み込みハイパーバイザを利用!
suites:
- name: client
provisioner:
run_list: recipe[foo::client_only]
- name: server
provisioner:
run_list: recipe[foo]
Q: CI サーバで Test Kitchen を見たことがありますか? 実装のよいパターンですか?
A: はい。CI 環境で Test Kitchen を実行している人がいます。価値を提供する一連のテストの自動化が次の論理的な手順となるでしょう。もっとも単純な手順は、CI タスクとして kitchen test --destroy=always を実行することです。--concurrency フラグを追加すると、より高速化できるでしょう(デフォルトではすべてのインスタンスを直列に実行します)。
Poise Ruby Cookbook のように Docker ドライバを使って CI で Test Kitchen を実行しているオープンソースの Cookbook の数が増えています。Chef 社のプロジェクトも Test Kitchen を通して EC2 ドライバを使って 自身のテスト を行っています。
Q: おすすめは .kitchen.yml と .kitchen.local.yml のどちらですか?
A: 好みはバージョン管理システムに適度な .kitchen.yml をコミットすることから始めます。相棒やチーム、オープンソースならば全世界と共有するのに十分な内容になります。独自の Credential をローカルに上書きしたり追加したりしたいときに .kitchen.local.yml を使います。それらを誤って .kitchen.yml ファイルに追加してコミットすることを防げます。.kitchen.local.yml は Cookbook 作者が選んだドライバを上書きすることにも使えます。例えば、Digital Ocean ドライバを使ってすべてをクラウド上で実施するより、Docker ドライバでトライアンドエラーするほうがよいこともあるでしょう。
Q: Serverspec テストのような「検証」を Test Kitchen で行うにはどうすればよいですか?
A: それを行う最も簡単な方法の1つは、ChefDK で実現できます。generate cookbook sample として Cookbook を生成すると、default_spec.rb ファイルを含んだ test/integration/default/serverspec という長いディレクトリパスを見つけるでしょう。test/integration/[スイート名]/serverspec 以下にあるファイルは kitchen verify がソフトウェアのインストール、テストファイルのアップロード、Serverspec の実行を十分なものとしてくれます。
あらゆる時点で、Test Kitchen が検証テストを実行するステップである kitchen verify を実行することができるでしょう。kitchen test も検証を行いますが、最初にクリーンなインスタンスを作成するところから始めることに注意してください。
Q: Cookbook を書いた後で Test Kitchen を使う際の何かアドバイスはありますか? 巨大な単一レポジトリや相互依存などなど、スパゲティコードがあるんです。ベストプラクティスはありますか?
A: いくつかの戦略がありますが、chef-repo を持っているなら(例えば cookbooks/ や data_bags/ などのディレクトリを持つ git レポやプロジェクト)、単純にプロジェクトのルートに .kitchen.yml を配置するだけです。もしルートに Berksfile や Cheffile がなければ、Test Kitchen はデフォルトで ./cookbooks/ ディレクトリ、Role や Data Bag などのディレクトリも同様に扱います。Node ごとのスイートを設定するなら、それぞれの Run-List を設定します:
---
driver:
name: vagrant
platforms:
- name: centos-7.1 # 単一プラットフォームを想定
suites:
- name: db
provisioner:
run_list:
- role[base]
- recipe[mysql::server]
- name: web
provisioner:
run_list:
- role[base]
- recipe[apache2]
副 Cookbook にも .kitchen.yml を配置でき、その Cookbook を独立して扱います。デフォルトでは、Test Kitchen は Cookbook の metadata.rb ファイルを依存関係の解決のために利用します(とても古いプロジェクトだと、ほとんど列挙されていません)。この点から、インスタンスを走らせるまでは metadata.rb に Cookbook の依存関係を追加することができます。これはブログ記事にちょうどよいでしょう----つまり単純ではないということです。ただし、Test Kitchen は記述されていない依存関係もうまいこと検出してくれます。
Q: ローカルのアプリ開発のテストに役立てるのに、直接 Vagrant を使う代わりに Test Kitchen を使うことはできますか? Box を取得し、コードベースからブランチを取得して実行するために vBox インスタンスに変数を渡すように vagrant up などを行っています。Test Kitchen でも同じようなことができますか?
A: はい、あなたのしていることは、少なくともいくつかの Chef 社の内部プロジェクトで使っているパターンです。もし Vagrant システムの準備に Chef を使っているなら、既にほぼ問題ない状態です。アプリのあるべきバージョンを指定しているだろう固定値の設定や環境変数に、Chef の Attribute を使うことをお勧めします。高度なテクニック: デフォルトでは、Test Kitchen は kitchen.yml や kitchen.local.yml ファイルを読み込む前に ERb を通して渡します。そのため、次のようなことができます:
driver:
name: vagrant
provisioner:
name: chef_zero
attributes:
my_app:
git_ref: <%= ENV.fetch("MY_APP_GIT_REF", "master") %>
この例では、Git のリファレンスを取得するのに環境変数 MY_APP_GIT_REF の値を使うか、変数が設定されていなければデフォルト値として master を使います。
Q: Test Kitchen は開発している Cookbook の実行のみに使うべきですか? それとも、最終的にローカルで box を構築するための多数の異なる Cookbook を収束するために Test Kitchen を使えますか? Test Kitchen を単一の Cookbook を動作するようにのみ使うべきか、最終成果物のサーバを収束させるために必要な多数の Cookbook や Role を使うべきか、確信がないのです。
A: 理想では、Test Kitchen はどちらでも使えます。そのため、単一の Cookbook を動作させるときは、Cookbook をソフトウェアの 1つの単位として扱って実行しています。しかし、完全なインフラをデプロイするときは、完全な Node か「Role」レベルで取り扱いたいと思います。つまり、高レベルなラッパー Cookbook か、古典的な Chef Role を使ってみましょう。この 2つの方法で、個別の Cookbook をより素直(つまり他の Cookbook に対して隔離された、単一の目的で、直行した状態)に、より両立でき、他の用途に再利用可能な形で扱えるはずです。
Q: デフォルトではどのプラットフォームが ChefDK をサポートしていますか? Unix ならどのようなものですか?
A: 2015 年夏の現在では、ダウンロード可能なパッケージ済の ChefDK は次の通りです。
- Mac OS X
- Red Hat Enterprise Linux/CentOS
- Windows (Desktop と Server)
- Ubuntu Linux
- Debian
Q: 単一の VM にウェブサーバを、2つの VM にアプリサーバをインストールしようとしています。これら 3つの VM に Test Kitchen を使えますか? もし使えるなら、.kitchen.yml ファイルはどのように指定しますか?
A: 現時点での Test Kitchen はマルチノードをサポートしていません。ただし、似たようなことを行う方法があります。異なる Node Role タイプを記述するように Suite を使って .kitchen.yml を構築できます:
---
driver:
name: vagrant
provisioner:
name: chef_zero
platforms:
- name: centos-7.1
suites:
- name: db-1
driver:
network:
- ["private_network", {ip: "192.168.33.10"}]
provisioner:
run_list: recipe[my_app::db_server]
- name: app-1
provisioner:
run_list: recipe[my_app::app_server]
driver:
network:
- ["private_network", {ip: "192.168.33.11"}]
- name: app-2
provisioner:
run_list: recipe[my_app::app_server]
driver:
network:
- ["private_network", {ip: "192.168.33.12"}]
次のような Test Kitchen インスタンスを起動します。
> kitchen list
Instance Driver Provisioner Verifier Transport Last Action
db-1-centos-71 Vagrant ChefZero Busser Ssh
app-1-centos-71 Vagrant ChefZero Busser Ssh
app-2-centos-71 Vagrant ChefZero Busser Ssh
正しい順番でインスタンスを起動すれば、マルチノードデプロイと似たようなことができます。しかし、まったく理想的でないでしょう。つまり、プロジェクトに Rakefile か kitchen コマンドを抽出するコマンドラインツールを追加すればうまくいきます。やりかたはいろいろあります。
Q: 事前準備として VirtualBox も必要ですか? 以前に Test Kitchen を試したときにはそうなっていました。
A: もし ChefDK に同梱されている Vagrant ドライバを使っているなら、その通りです。VirtualBox は必須の依存関係です。しかし、私はいつも VMware Fusion Vagrant プロバイダを使っています。これは有料ライセンスが必要な vagrant-fusion プラグインと、やはり有料ライセンスが必要な VMware Fusion がインストールされていなければいけません。
VirtualBox や Vagrant 以外のクラウドベースのドライバは EC2、Digital Ocean、Rackspace などがあります。
Q: 既存の rvm システムと統合できますか?
A: Test Kitchen のことを言っているなら、できます。Test Kitchen は RVM、rbenv、shrubby などの Ruby 切り替え器でうまく動作します。私は Test Kitchen のコード開発や Cookbook 開発で、Ruby バージョン間を戻したり進めたりできる chruby を使っています。
ChefDK パッケージは独自バージョンの Ruby を含んでいて、/usr/bin/kitchen シンボリックリンクとしてインストールされているプログラムは /opt/chef/embedded パス以下の Ruby を使っています。Joshua Timberman が、主要な開発環境として ChefDK の Ruby をどのように使っているかというよい ブログ記事 を投稿しています。
Q: 一度に 100 も動かしたくないしメモリをだめにしたくないで、--concurrency=4 というのはどうですか?
A: よい質問です----デフォルトでは kitchen converge --concurrency は一度に 1スレッドにすべてのインスタンスを実行します。もし 100 インスタンスあるなら、もうめちゃくちゃなことになります。Vagrant ドライバなどを使っているなら、メモリが食い潰されてしまうでしょう。--concurrency フラグは並列実行するインスタンス数の制限をサポートしているので、あなたのシステムに合った指定をしてください。
Q: metadata.rb に他の Cookbook の依存関係を定義するという話がありました。でも、Berkshelf で同じように変更や追加する話がありませんでした。それで、依存関係を解決するために必要な手続きはどうすればよいですか?
A: Cookbook の依存関係を解決してダウンロードするために Berkshelf を使うという考えはとても正しいです。chef generate cookbook で Cookbook を生成したら、生成された Berksfile は次のようになります。
source 'https://supermarket.chef.io'
metadata
これが ChefDK の chef コマンドを使って Cookbook を生成する理由の 1つです(実は他にもありますが)。これによって、開発の初期段階はより早くなるでしょう。
Q: 収束時間を節約するために、Test Kitchen がダウンロードするパッケージをキャッシュしておく簡単な方法はありますか? ローカルキャッシュプロキシをインストールするいくつかのハックを github で見かけたくらいです。
A: 現時点で、さまざまなドライバやプラグインのすべてで確実な動作をする解決策はありません。コアツールにすべてを盛り込むのは気が進まないのです。高速化のために http プロキシキャッシュを有効にするいくつかの裏技があるので(私自身も gist のような方法を使っています)、収束を高速化する方法を調査するのに今後もより多くの時間を使っていくと思います。
Q: Test Kitchen は Recipe を Test Kitchen で走らせるためのヒント(node.kitchen ?)を提供していません。Test Kitchen をモックアップのサービスと組み合わせた開発環境として利用するベストプラクティスはありますか?
A: Test Kitchen がヒントを明示する方法がないというのは正しいです。これはデザイン上の都合です。Chef を実行する前にいくつか異なる動作モードを選択する方法を考えてみましょう。例えば、Test Kitchen インスタンス内で実行していることを検知してモックアップサービスを有効にしたい場合、次のようにして Chef に直接伝えることができるでしょう:
---
driver:
name: vagrant
provisioner:
name: chef_zero
attributes:
my_cookbook:
mock_services: true
platforms:
- name: ubuntu-14.04
suites:
- name: default
run_list:
- recipe[my_cookbook]
node["my_cookbook"]["mock_services"] のデフォルトを false か nil に設定し、Cookbook は「default」か「normal」モードを「mocked」モードの逆として取り扱うだけです。このモードの取り扱いは本番環境とは異なるので、Cookbook はちょっと違ったコードパスとして実行することに注意してください。
Q: docker プロバイダは独自の docker 実装に紐付いていますか、それとも既存の boot2docker に対する docker クライアントを使っていますか?
A: Docker ドライバ は現時点では Workstation 上の docker バイナリをシェル実行していて、DOCKER_HOST 環境変数を尊重しています。Windows において、このセッションの Workstation 部分では、docker-machine を使った Docker マシンを Mac に設定し、Windows VM に設定をエクスポートしているので、Windows VM 内で Docker VM を動作させているのではありません。
Q: vagrant-lxc ドライバは使えますか?
A: Vagrant ドライバ を使えばできます。:provider に「lxc」を設定するか、DEFAULT_VAGRANT_PROVIDER=lxc を設定して :driver ブロックを次のようにする必要があります:
---
driver:
name: vagrant
provider: lxc
customize:
container_name: mysql
backingstore: lvm
backingstore_options:
- [vgname, schroot]
provisioner:
name: chef_zero
platforms:
- ubuntu-15.04
suites:
- name: default
Q: docker ドライバとサービスの問題についての話で、修正方法がありました。この件について知るにはどこを見たらいいですか?
A: プラットフォームのタイプとバージョンによります。多くの Linux ディストリビューションで systemd の採用の度合いに違いがあることに注意してください。pid=1 プロセスとして sshd を動作させるより init システムを動作させるなら、:driver ブロックに run_command: /sbin/init を設定することができるでしょう。
Q: chef コマンドを使った Cookbook の生成方法と、Berkshelf での Cookbook の生成方法があります。どちらの方法がお勧めですか?
A: よい質問です。選択はあなた次第ですが、最近は ChefDK に含まれている chef ジェネレータがうまくやってくれると思います。独自の Cookbook ジェネレータを作成する方法が ドキュメントサイト に載っています。
Q: Test Kitchen での packer についての考えを聞かせてください。
A: Packer はすばらしいもので、複数のイメージを正確に作成する能力があります。事実、kitchen-vagrant がデフォルトで利用する Vagrant basebox を作成するための Bento プロジェクト では Packer を積極的に利用しています。
Test Kitchen をイメージ作成に使っているなら、Packer には重複する箇所があります。意図していなくても Test Kitchen のデフォルトフローはそれを実行するようになっています。今のところ、kitchen-packer ドライバがどんなものになるだろうと思っています 🙂
Q: .kitchen.yml で指定できるすべての Attribute はどこに書いてありますか?
A: いくつかの例を挙げて詳しく解説している Chef ドキュメントサイト に長大な .kitchen.yml ページがあります。この努力に加えて、Test Kitchen ウェブサイト に基本的な .kitchen.yml のリファレンスマニュアルを追加しようと思っているのですが、一旦保留となっています。
結局、さまざまなドライバやプラグインに対して利用可能な Attribute 設定を発見するには、kitchen diagnose をよく使っています。通例、「kitchen diagnose で表示される Attribute は上書きできるだろう」という理論が適用できます。
Q: これら 3つの環境を設定する手順を共有してくれますか?
A: わかりました。GitHub の fnichol/feedback-factory-webinar-cookbook に Cookbook を push しました。お役に立てば幸いです。
Q: 異なる Role/Recipe を異なる Environment と Data Bag を使って実行するために異なる VM を起動しようとしています。これを満たす .kitchen.yml はどう書けばいいですか?
A: Test Kitchen が roles/ や environments/ といったディレクトリのパスを取得するときには、フォールバックの検知ロジックがあります。例えば、次のような .kitchen.yml で「server」というスイートを設定してみましょう:
---
driver:
name: vagrant
provisioner:
name: chef_zero
platforms:
- name: ubuntu-15.04
suites:
- name: server
Role を使う Cookbook をテストしたいとするなら、Test Kitchen は次のような存在しているディレクトリをまず使います:
- ./test/integration/server/roles
- ./test/integration/roles
- ./roles
この方法で、必要ならば各スイートごとに分割した Role や Environment の設定が行えます。
Q: VM で Windows や Red Hat OS を使いたい場合はどうすればいいですか?
A: Windows や Red Hat Enterprise Linux のような有料 OS を実行する最も手っ取り早い方法は、EC2 ドライバ やその他のクラウドベースのドライバを使うことです。通常、ライセンス料金全額ではなく、時間単位の課金で利用できます。
ちょっと変更の必要があるなら、Chef 社の Bento プロジェクト で Vagrant base box の構築を試してみるといいでしょう。Mac OS X、Suse Enterprise Linux、Red Hat Enterprise Linux、Solaris といったいくつかの有料 OS を構築するためのテンプレートを用意しています。そんなに遠くない将来に、Windows テンプレートを準備したいと考えています。
Q: それらはローカルの仮想マシンですか、それともクラウド上ですか?
A: この webinar セッションで使ったすべての仮想マシンは次のところにあります:
- 1つ目の例では、Mac Workstation 内の Vagrant を使ってローカルの仮想マシンを起動しました。
- 2つ目の例では、Mac Workstation 内の Vagrant 仮想マシン内で Windows を実行し、これも Mac Workstation 内の VMware Fusion 仮想マシン内で Docker コンテナを起動しました。
- 最後の例では、Amazon EC2 インスタンスの Debian を実行し、Amazon AWS クラウドで他の EC2 インスタンスを起動しました。
次回は図を用意しようと思います 🙂
Q: Exchange や Sharepoint、AC DC などといった複雑なライセンスの Windows ソフトウェアを Chef を使ってインストールと管理を行う方法をこのプレゼンで知りたいと思います。ちょっとしたことではなく大規模なことだと思いますが...
A: そうですね、Chef を使って Windows 関連のサービスを管理したいという企業はたくさんあります。Test Kitchen に多くの努力がなされた結果、Windows Node で Chef Cookbook をテストするのはとても簡単になりました。これらのツールが今後さらに改善されて、より効果的に、より早く、より楽しく、Windows インフラの自動化の助けとなることが私達の希望です。