序章

InSpec は、規制上の懸念、推奨事項、または要件を記述およびテストするために使用される、オープンソースの監査および自動テストフレームワークです。 人間が読める形式で、プラットフォームに依存しないように設計されています。 開発者は、ローカルでInSpecを使用するか、SSH、WinRM、またはDockerを使用してテストを実行できるため、テスト対象のインフラストラクチャにパッケージをインストールする必要はありません。

InSpecを使用すると、サーバー上で直接テストを実行できますが、インフラストラクチャに問題を引き起こす可能性のある人為的エラーの可能性があります。 このシナリオを回避するために、開発者は Kitchen を使用して仮想マシンを作成し、テストが実行されているマシンに選択したOSをインストールできます。 Kitchenは、テストランナー、つまりテスト自動化ツールであり、1つ以上の分離されたプラットフォームでインフラストラクチャコードをテストできます。 また、多くのテストフレームワークをサポートし、Vagrant、AWS、DigitalOcean、Docker、LXCコンテナーなどのさまざまなプラットフォーム用のドライバープラグインアーキテクチャに柔軟に対応します。

このチュートリアルでは、DigitalOceanUbuntu18.04ドロップレットで実行されているAnsibleプレイブックのテストを作成します。 テストランナーとしてKitchenを使用し、テストを作成するためにInSpecを使用します。 このチュートリアルを終了するまでに、AnsiblePlaybookのデプロイをテストできるようになります。

前提条件

このガイドを開始する前に、以下に加えてDigitalOceanアカウントが必要です。

ステップ1—キッチンのセットアップと初期化

キッチンに同梱されている前提条件の一部としてChefDKをインストールしました。 このステップでは、DigitalOceanと通信するようにKitchenを設定します。

Kitchenを初期化する前に、プロジェクトディレクトリを作成して移動します。 このチュートリアルでは、これを呼び出します ansible_testing_dir.

次のコマンドを実行して、ディレクトリを作成します。

  1. mkdir ~/ansible_testing_dir

そしてそれに移動します:

  1. cd ~/ansible_testing_dir

使用する gem kitchen-digitaloceanパッケージをローカルマシンにインストールします。 これはあなたが言うことを可能にします kitchen テストの実行時にDigitalOceanドライバーを使用するには:

  1. gem install kitchen-digitalocean

プロジェクトディレクトリ内で、 kitchen init コマンド指定 ansible_playbook プロビジョニング担当者として digitalocean キッチンを初期化するときのドライバーとして:

  1. kitchen init --provisioner=ansible_playbook --driver=digitalocean

次の出力が表示されます。

Output
create kitchen.yml create chefignore create test/integration/default

これにより、プロジェクトディレクトリ内に次のものが作成されました。

  • test/integration/default テストファイルを保存するディレクトリです。

  • chefignore は、特定のファイルが Chef Infra Server にアップロードされないようにするために使用するファイルですが、このチュートリアルでは使用しません。

  • kitchen.yml テスト構成(テストする対象とターゲットプラットフォーム)を説明するファイルです。

次に、CLIからドロップレットを作成するためのアクセス権を取得するために、DigitalOceanクレデンシャルを環境変数としてエクスポートする必要があります。 まず、次のコマンドを実行して、DigitalOceanアクセストークンから開始します。

  1. export DIGITALOCEAN_ACCESS_TOKEN="YOUR_DIGITALOCEAN_ACCESS_TOKEN"

SSHキーID番号も取得する必要があります。 ご了承ください YOUR_DIGITALOCEAN_SSH_KEY_IDS シンボリック名ではなく、SSHキーの数値IDである必要があります。 DigitalOcean APIを使用すると、次のコマンドでキーの数値IDを取得できます。

  1. curl -X GET https://api.digitalocean.com/v2/account/keys -H "Authorization: Bearer $DIGITALOCEAN_ACCESS_TOKEN"

このコマンドから、SSHキーと関連するメタデータのリストが表示されます。 出力を読んで正しいキーを見つけ、出力内のID番号を特定します。

Output
... {"id":your-ID-number,"fingerprint":"fingerprint","public_key":"ssh-rsa your-ssh-key","name":"your-ssh-key-name" ...

注:出力を読みやすくして数値IDを取得したい場合は、検索してダウンロードできます。 jq jqダウンロードページのOSに基づいています。 これで、パイプされた前のコマンドを実行できます jq 次のように:

  1. curl -X GET https://api.digitalocean.com/v2/account/keys -H "Authorization: Bearer $DIGITALOCEAN_ACCESS_TOKEN" | jq

SSHキー情報は次のようにフォーマットされています。

Output
{ "ssh_keys": [ { "id": YOUR_SSH_KEY_ID, "fingerprint": "2f:d0:16:6b", "public_key": "ssh-rsa AAAAB3NzaC1yc2 [email protected]", "name": "sannikay" } ], }

SSH数値IDを特定したら、次のコマンドを使用してそれらをエクスポートします。

  1. export DIGITALOCEAN_SSH_KEY_IDS="YOUR_DIGITALOCEAN_SSH_KEY_ID"

初期化しました kitchen DigitalOceanクレデンシャルの環境変数を設定します。 次に、コマンドラインから直接DigitalOceanドロップレットでテストを作成して実行します。

ステップ2—AnsiblePlaybookを作成する

このステップでは、プレイブックとロールを作成し、によって作成されたドロップレットにNginxとNode.jsを設定します。 kitchen 次のステップで。 プレイブックで指定された条件が満たされていることを確認するために、プレイブックに対してテストが実行されます。

まず、作成します roles NginxとNode.jsの両方の役割のディレクトリ:

  1. mkdir -p roles/{nginx,nodejs}/tasks

これにより、次のようなディレクトリ構造が作成されます。

roles
├── nginx
│   └── tasks
└── nodejs
    └── tasks

次に、を作成します main.yml のファイル roles/nginx/tasks お好みのエディタを使用したディレクトリ:

  1. nano roles/nginx/tasks/main.yml

このファイルで、次のコンテンツを追加してNginxをセットアップおよび起動するタスクを作成します。

ロール/nginx/tasks/main.yml
---
- name: Update cache repositories and install Nginx
  apt:
    name: nginx
    update_cache: yes

- name: Change nginx directory permission
  file:
    path: /etc/nginx/nginx.conf
    mode: 0750

- name: start nginx
  service:
    name: nginx
    state: started

コンテンツを追加したら、ファイルを保存して終了します。

roles/nginx/tasks/main.yml、Dropletのキャッシュリポジトリを更新するタスクを定義します。これは、 apt update サーバー上で手動でコマンドを実行します。 このタスクは、Nginx構成ファイルのアクセス許可も変更し、Nginxサービスを開始します。

また、作成します main.yml のファイル roles/nodejs/tasks Node.jsを設定するタスクを定義するには:

  1. nano roles/nodejs/tasks/main.yml

このファイルに次のタスクを追加します。

ロール/nodejs/tasks/main.yml
---
- name: Update caches repository
  apt:
    update_cache: yes

- name: Add gpg key for NodeJS LTS
  apt_key:
    url: "https://deb.nodesource.com/gpgkey/nodesource.gpg.key"
    state: present

- name: Add the NodeJS LTS repo
  apt_repository:
    repo: "deb https://deb.nodesource.com/node_{{ NODEJS_VERSION }}.x {{ ansible_distribution_release }} main"
    state: present
    update_cache: yes

- name: Install Node.js
  apt:
    name: nodejs
    state: present

終了したら、ファイルを保存して終了します。

roles/nodejs/tasks/main.yml、最初に、Dropletのキャッシュリポジトリを更新するタスクを定義します。 次に、次のタスクで、Node.jsの信頼性を検証する手段として機能するNode.jsのGPGキーを追加します。 apt リポジトリ。 最後の2つのタスクはNode.jsを追加します apt リポジトリを作成し、Node.jsをインストールします。

次に、変数、ロールを実行する順序、スーパーユーザー特権設定などのAnsible構成を定義します。 これを行うには、という名前のファイルを作成します playbook.yml、キッチンの入り口として機能します。 テストを実行すると、Kitchenは playbook.yml ファイルを作成し、実行する役割を探します。 roles/nginx/tasks/main.ymlroles/nodejs/tasks/main.yml ファイル。

次のコマンドを実行して作成します playbook.yml:

  1. nano playbook.yml

次のコンテンツをファイルに追加します。

ansible_testing_dir / playbook.yml
---
 - hosts: all
   become: true
   remote_user: ubuntu
   vars:
    NODEJS_VERSION: 8

ファイルを保存して終了します。

プレイブックで指定された条件が満たされていることを確認するためにテストを実行するAnsibleプレイブックの役割を作成しました。

ステップ3—InSpecテストを作成する

このステップでは、Node.jsがDropletにインストールされているかどうかを確認するためのテストを作成します。 テストを作成する前に、InSpecテストの例の形式を見てみましょう。 多くのテストフレームワークと同様に、InSpecコードは自然言語に似ています。 InSpecには、調査対象と対象の予想される状態の2つの主要なコンポーネントがあります。

ブロックA
describe '<entity>' do
  it { <expectation> }
end

ブロックAでは、キーワード doend ブロックを定義します。 The describe キーワードは一般にテストスイートと呼ばれ、テストケースが含まれています。 The it キーワードは、テストケースを定義するために使用されます。

<entity> パッケージ名、サービス、ファイル、ネットワークポートなど、調べたい件名です。 The <expectation> 目的の結果または期待される状態を指定します。たとえば、Nginxをインストールするか、特定のバージョンにする必要があります。 InSpec DSLドキュメントをチェックして、InSpec言語の詳細を確認できます。

InSpecテストブロックの別の例:

ブロックB
control 'Can be anything unique' do  
  impact 0.7                         
  title 'A human-readable title'     
  desc  'An optional description'
  describe '<entity>' do             
    it { <expectation> }
  end
end

ブロックAとブロックBの違いは control ブロック。 The control ブロックは、規制管理、推奨、または要件の手段として使用されます。 The control ブロックには名前があります。 通常、一意のID、メタデータなど desc, title, impact、そして最後に関連するグループ describe チェックを実装するためのブロック。

desc, title、 と impact コントロールの重要性とその目的を、簡潔で完全な説明とともに完全に説明するメタデータを定義します。 impact からの範囲の数値を定義します 0.01.0 どこ 0.0<0.01 影響なしとして分類され、 0.01<0.4 低影響として分類され、 0.4<0.7 中程度の影響として分類され、 0.7<0.9 影響が大きいと分類され、 0.91.0 クリティカルコントロールとして分類されます。

次に、テストを実装します。 ブロックAの構文を使用して、InSpecのpackageリソースを使用して次のことをテストします。 Node.js システムにインストールされています。 次の名前のファイルを作成します sample.rb あなたの中で test/integration/default テスト用のディレクトリ。

作成 sample.rb:

  1. nano test/integration/default/sample.rb

ファイルに以下を追加します。

test / Integration / default / sample.rb
describe package('nodejs') do
  it { should be_installed }
end

ここであなたのテストは使用しています package Node.jsをチェックするためのリソースがインストールされています。

終了したら、ファイルを保存して終了します。

このテストを実行するには、編集する必要があります kitchen.yml 以前に作成したプレイブックを指定し、構成に追加します。

あなたの kitchen.yml ファイル:

  1. nano ansible_testing_dir/kitchen.yml

のコンテンツを置き換えます kitchen.yml 次のように:

ansible_testing_dir / kitchen.yml
---
driver:
  name: digitalocean

provisioner:
  name: ansible_playbook
  hosts: test-kitchen
  playbook: ./playbook.yml

verifier:
  name: inspec

platforms:
  - name: ubuntu-18
    driver_config:
      ssh_key: PATH_TO_YOUR_PRIVATE_SSH_KEY
      tags:
        - inspec-testing
      region: fra1
      size: 1gb
      private_networking: false
    verifier:
      inspec_tests:
        - test/integration/default
suites:
  - name: default

The platform オプションには次のものがあります。

  • name:使用している画像。

  • driver_config:DigitalOceanドロップレット構成。 次のオプションを指定しています driver_config:

    • ssh_key:へのパス YOUR_PRIVATE_SSH_KEY. 君の YOUR_PRIVATE_SSH_KEY を作成するときに指定したディレクトリにあります ssh 鍵。
    • tags:ドロップレットに関連付けられているタグ。
    • regionregion ドロップレットをホストする場所。
    • size:ドロップレットに持たせたいメモリ。
  • verifier:これは、プロジェクトにInSpecテストが含まれていることを定義します。

    • The inspec_tests 一部は、テストがプロジェクトの下に存在することを指定します test/integration/default ディレクトリ。

に注意してください nameregion 略語を使用します。 使用できる略語については、test-kitchenのドキュメントを確認してください。

構成を追加したら、ファイルを保存して終了します。

を実行します kitchen test テストを実行するコマンド。 これにより、Node.jsがインストールされているかどうかが確認されます。現在、Node.jsの役割がないため、意図的に失敗します。 playbook.yml ファイル:

  1. kitchen test

次のような出力が表示されます。

Output: failing test results
-----> Starting Kitchen (v1.24.0) -----> Cleaning up any prior instances of <default-ubuntu-18> -----> Destroying <default-ubuntu-18>... DigitalOcean instance <145268853> destroyed. Finished destroying <default-ubuntu-18> (0m2.63s). -----> Testing <default-ubuntu-18> -----> Creating <default-ubuntu-18>... DigitalOcean instance <145273424> created. Waiting for SSH service on 138.68.97.146:22, retrying in 3 seconds [SSH] Established (ssh ready) Finished creating <default-ubuntu-18> (0m51.74s). -----> Converging <default-ubuntu-18>... $$$$$$ Running legacy converge for 'Digitalocean' Driver -----> Installing Chef Omnibus to install busser to run tests PLAY [all] ********************************************************************* TASK [Gathering Facts] ********************************************************* ok: [localhost] PLAY RECAP ********************************************************************* localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 Downloading files from <default-ubuntu-18> Finished converging <default-ubuntu-18> (0m55.05s). -----> Setting up <default-ubuntu-18>... $$$$$$ Running legacy setup for 'Digitalocean' Driver Finished setting up <default-ubuntu-18> (0m0.00s). -----> Verifying <default-ubuntu-18>... Loaded tests from {:path=>". ansible_testing_dir.test.integration.default"} Profile: tests from {:path=>"ansible_testing_dir/test/integration/default"} (tests from {:path=>"ansible_testing_dir.test.integration.default"}) Version: (not specified) Target: ssh://[email protected]:22 System Package nodejs × should be installed expected that System Package nodejs is installed Test Summary: 0 successful, 1 failure, 0 skipped >>>>>> ------Exception------- >>>>>> Class: Kitchen::ActionFailed >>>>>> Message: 1 actions failed. >>>>>> Verify failed on instance <default-ubuntu-18>. Please see .kitchen/logs/default-ubuntu-18.log for more details >>>>>> ---------------------- >>>>>> Please see .kitchen/logs/kitchen.log for more details >>>>>> Also try running `kitchen diagnose --all` for configuration 4.54s user 1.77s system 5% cpu 2:02.33 total

プロビジョニングしたドロップレットにNode.jsがインストールされていないため、テストが失敗していることが出力に示されます kitchen. を追加してテストを修正します nodejs あなたへの役割 playbook.yml ファイルを作成して、テストを再実行してください。

編集します playbook.yml 含めるファイル nodejs 役割:

  1. nano playbook.yml

次の強調表示された行をファイルに追加します。

ansible_testing_dir / playbook.yml
---
 - hosts: all
   become: true
   remote_user: ubuntu
   vars:
    NODEJS_VERSION: 8

   roles:
    - nodejs

ファイルを保存して閉じます。

次に、を使用してテストを再実行します kitchen test 指図:

  1. kitchen test

次の出力が表示されます。

Output
...... Target: ssh://[email protected]:22 System Package nodejs ✔ should be installed Test Summary: 1 successful, 0 failures, 0 skipped Finished verifying <default-ubuntu-18> (0m4.89s). -----> Destroying <default-ubuntu-18>... DigitalOcean instance <145512952> destroyed. Finished destroying <default-ubuntu-18> (0m2.23s). Finished testing <default-ubuntu-18> (2m49.78s). -----> Kitchen is finished. (2m55.14s) 4.86s user 1.77s system 3% cpu 2:56.58 total

Node.jsを使用してインストールしているため、テストに合格します。 nodejs 役割。

これがキッチンが行っていることの要約です Test Action:

  • ドロップレットが存在する場合は破棄します
  • ドロップレットを作成します
  • ドロップレットを収束します
  • InSpecでドロップレットを検証します
  • ドロップレットを破壊します

問題が発生した場合、KitchenはDropletの実行を中止します。 これは、Ansibleプレイブックが失敗した場合、InSpecが実行されず、Dropletが破棄されないことを意味します。 これにより、インスタンスの状態を検査して問題を修正する機会が得られます。 必要に応じて、最終的な破棄アクションの動作をオーバーライドできます。 のCLIヘルプを確認してください --destroy を実行してフラグを立てます kitchen help test 指図。

最初のテストを作成し、問題を修正する前に1つのインスタンスが失敗した状態で、プレイブックに対して実行しました。 次に、テストファイルを拡張します。

ステップ4—テストケースを追加する

このステップでは、テストファイルにさらにテストケースを追加して、NginxモジュールがDropletにインストールされており、構成ファイルに適切な権限があるかどうかを確認します。

あなたの編集 sample.rb さらにテストケースを追加するファイル:

  1. nano test/integration/default/sample.rb

次のテストケースをファイルの最後に追加します。

test / Integration / default / sample.rb
. . .
control 'nginx-modules' do
  impact 1.0
  title 'NGINX modules'
  desc 'The required NGINX modules should be installed.'
  describe nginx do
    its('modules') { should include 'http_ssl' }
    its('modules') { should include 'stream_ssl' }
    its('modules') { should include 'mail_ssl' }
  end
end

control 'nginx-conf' do
  impact 1.0
  title 'NGINX configuration'
  desc 'The NGINX config file should owned by root, be writable only by owner, and not writeable or and readable by others.'
  describe file('/etc/nginx/nginx.conf') do
    it { should be_owned_by 'root' }
    it { should be_grouped_into 'root' }
    it { should_not be_readable.by('others') }
    it { should_not be_writable.by('others') }
    it { should_not be_executable.by('others') }
  end
end

これらのテストケースは、 nginx-modules ドロップレットに含める http_ssl, stream_ssl、 と mail_ssl. あなたもチェックしています /etc/nginx/nginx.conf ファイルのアクセス許可。

両方を使用しています itits テストを定義するキーワード。 キーワード its リソースのプロパティにアクセスするためにのみ使用されます。 例えば、 modules のプロパティです nginx.

テストケースを追加したら、ファイルを保存して終了します。

今実行します kitchen test 再度テストするコマンド:

  1. kitchen test

次の出力が表示されます。

Output
... Target: ssh://[email protected]:22 ↺ nginx-modules: NGINX modules ↺ The `nginx` binary not found in the path provided. × nginx-conf: NGINX configuration (2 failed) × File /etc/nginx/nginx.conf should be owned by "root" expected `File /etc/nginx/nginx.conf.owned_by?("root")` to return true, got false × File /etc/nginx/nginx.conf should be grouped into "root" expected `File /etc/nginx/nginx.conf.grouped_into?("root")` to return true, got false ✔ File /etc/nginx/nginx.conf should not be readable by others ✔ File /etc/nginx/nginx.conf should not be writable by others ✔ File /etc/nginx/nginx.conf should not be executable by others System Package nodejs ✔ should be installed Profile Summary: 0 successful controls, 1 control failure, 1 control skipped Test Summary: 4 successful, 2 failures, 1 skipped

一部のテストが失敗していることがわかります。 あなたはそれらを追加することによってそれらを修正するつもりです nginx プレイブックファイルへの役割とテストの再実行。 失敗したテストでは、次のことを確認しています。 nginx 現在サーバーに存在しないモジュールとファイルのアクセス許可。

あなたの playbook.yml ファイル:

  1. nano ansible_testing_dir/playbook.yml

次の強調表示された行を役割に追加します。

ansible_testing_dir / playbook.yml
---
- hosts: all
  become: true
  remote_user: ubuntu
  vars:
  NODEJS_VERSION: 8

  roles:
  - nodejs
  - nginx

終了したら、ファイルを保存して閉じます。

次に、テストを再度実行します。

  1. kitchen test

次の出力が表示されます。

Output
... Target: ssh://[email protected]:22 ✔ nginx-modules: NGINX version ✔ Nginx Environment modules should include "http_ssl" ✔ Nginx Environment modules should include "stream_ssl" ✔ Nginx Environment modules should include "mail_ssl" ✔ nginx-conf: NGINX configuration ✔ File /etc/nginx/nginx.conf should be owned by "root" ✔ File /etc/nginx/nginx.conf should be grouped into "root" ✔ File /etc/nginx/nginx.conf should not be readable by others ✔ File /etc/nginx/nginx.conf should not be writable by others ✔ File /etc/nginx/nginx.conf should not be executable by others System Package nodejs ✔ should be installed Profile Summary: 2 successful controls, 0 control failures, 0 controls skipped Test Summary: 9 successful, 0 failures, 0 skipped

追加した後 nginx プレイブックへの役割すべてのテストに合格しました。 出力は、 http_ssl, stream_ssl、 と mail_ssl モジュールがDropletにインストールされ、構成ファイルに適切な権限が設定されます。

終了したら、またはドロップレットが不要になったら、を実行してドロップレットを破棄できます。 kitchen destroy テストの実行後に削除するコマンド:

  1. kitchen destroy

このコマンドに続いて、次のような出力が表示されます。

Output
-----> Starting Kitchen (v1.24.0) -----> Destroying <default-ubuntu-18>... Finished destroying <default-ubuntu-18> (0m0.00s). -----> Kitchen is finished. (0m5.07s) 3.79s user 1.50s system 82% cpu 6.432 total

プレイブックのテストを作成し、テストを実行し、失敗したテストを修正して、すべてのテストに合格していることを確認しました。 これで、仮想環境を作成し、Ansible Playbookのテストを作成し、Kitchenを使用して仮想環境でテストを実行する準備が整いました。

結論

これで、Ansibleデプロイメントをテストするための柔軟な基盤ができました。これにより、ライブサーバーで実行する前にプレイブックをテストできます。 テストをプロファイルにパッケージ化することもできます。 プロファイルを使用して、Githubまたは Chef Supermarket を介してテストを共有し、ライブサーバーで簡単に実行できます。

InSpecとKitchenのより包括的な詳細については、公式InSpecドキュメントおよび公式Kitchenドキュメントを参照してください。