1. 概要

クラウドサーバーサービス(IaaS)の性能比較・ディスク編~IOPSの計測~ の番外編です。

Vagrantでクラウド上にインスタンスを作成し、Ansibleでアプリインストール・実行・結果取得まで自動化します。
今回はIDCFクラウドを対象に記事をまとめます。

1.1 実行環境(ホスト側)

  • OS : Linux AMI release 2017.03
  • Vagrant : 1.9.4
  • Ansible : ansible 2.3.0.0

1.2 構築対象

  • Iaas: IDCFクラウド
  • OS:CentOS 7.3
  • インストール及び実行するアプリケーション: fio

2. 事前準備

2.1. Vagrantにdotenvプラグインをインストール

Vagrant上で .env から変数の読み込みができるように、dotenvプラグインをインストールしておきます。

$ vagrant plugin install dotenv

参考:dotenvを利用して環境ごとでVagrantfileの設定値を変更してみる

2.2 VagrantにCloudStackのプラグインをインストール

VagrantからIDCFクラウドのインスタンスを扱うために、CloudStackのプラグインをインストールします。
バージョン指定でインストールしています。

$ vagrant plugin install vagrant-cloudstack --plugin-version 1.3.0

3. Vagrantの設定

3.1 Vagrantfile

Vagrantの設定ファイルであるVagrantfile(最初は大文字、拡張子なし)を作成します。
以下の例では、CloudStackを使ってIDCFクラウド上に仮想サーバを作成し、完了後にAnsibleを呼び出しています。

Vagrantfile

Dotenv.load

Vagrant.configure(2) do |config|
  config.vm.box = "dummy"

  # CloudStack Setting For IDCF Cloud
  config.vm.provider :cloudstack do |cloudstack, override|

    # Dummy Box
    override.vm.box = "dummy"
    override.vm.box_url = "https://github.com/klarna/vagrant-cloudstack/raw/master/dummy.box"

    # API Parameters
    cloudstack.host                  = "compute.jp-east-2.idcfcloud.com"
    cloudstack.path                  = "/client/api"
    cloudstack.port                  = "443"
    cloudstack.scheme                = "https"
    cloudstack.api_key               = "#{ENV['CLOUDSTACK_API_KEY']}"
    cloudstack.secret_key            = "#{ENV['CLOUDSTACK_SECRET_KEY']}"
    expunge_on_destroy               = true

    # Virtual Machine Settings
    cloudstack.display_name          = "Vagrant-CentOS-7"
    cloudstack.template_name         = "CentOS 7.3 64-bit"
    cloudstack.zone_name             = "#{ENV['CLOUDSTACK_ZONE_NAME']}"
    cloudstack.service_offering_name = "#{ENV['COUDSTACK_SERVICE_OFFERING_NAME']}"

    # Network Settings
    cloudstack.pf_ip_address_id      = "#{ENV['CLOUDSTACK_PF_IP_ADDRESS_ID']}"
    cloudstack.pf_public_port        = "2201"
    cloudstack.keypair               = "#{ENV['CLOUDSTACK_SSH_KEYPAIR']}"
    override.ssh.private_key_path    = "#{ENV['VAGRANT_SSH_PRIVATE_KEY']}"
    override.ssh.username            = "#{ENV['VAGRANT_SSH_USERNAME']}"

    cloudstack.instance_ready_timeout = 1800
  end

  #
  # Run Ansible from the Vagrant Host
  #
  config.vm.provision "ansible" do |ansible|
    ansible.playbook                 = "site.yaml"
    ansible.inventory_path           = "hosts"
    ansible.limit = 'all'
    ansible.verbose = true
  end

end

CloudStack 参考 :
Vagrantを使ってCloudStack上の環境構築をしてみよう
vagrant-cloudstackを試してみた

Ansible呼び出し参考 :
Vagrant公式 : Ansible Provisioner

3.2 .env

認証情報等の変数を .env というファイルに記述し、.envはVagrantfileと同じ場所に保存しておきます。

CLOUDSTACK_API_KEY               = '**********'
CLOUDSTACK_SECRET_KEY            = '**********'
CLOUDSTACK_ZONE_NAME             = 'lux'
COUDSTACK_SERVICE_OFFERING_NAME  = 'light.S1'
CLOUDSTACK_PF_IP_ADDRESS_ID      = '**********'
CLOUDSTACK_SSH_KEYPAIR           = '**********'
VAGRANT_SSH_USERNAME             = 'root'
VAGRANT_SSH_PRIVATE_KEY          = '~/.ssh/id_rsa'
ANSIBLE_PLAYBOOK                 = 'site.yml'
ANSIBLE_INVENTORY_PATH           = 'hosts'

4. Ansibleの設定

4.1 Hostsファイル

Vagrantfileの中の ansible.inventory_path で指定した場所に置いておきます。今回の例では Vagrantfileと同じ階層にあります。

hosts

***.***.**.***:2201
  • Vagrantで作成する仮想マシンのIPアドレスを指定します。
  • Vagrantfileの中の cloudstack.pf_public_port でパブリックポートを 2201 に変更しているので、IPアドレスの後ろにポート番号を指定します。未指定の場合Ansibleはデフォルトの 22 でSSH接続するので、接続に失敗してしまいます。

参考:Ansible公式・Inventory

4.2 PlayBook

自動構築したい内容を、AnsibleのPlaybook(拡張子.yml)に書いていきます。

4.2.1 Role

AnsibleはPlaybookをRoleごとに分けて書くことができます。決まったルールで roles のディレクトリを構成しておくと、自動的にPlaybookに include される仕組みです。実行内容ごとにRoleを分けて作っておけば、可読性や再利用性が高まります。
今回はVagrantfileを含め以下のようなファイル配置にしました。

hosts
roles/
  iops/ # roleの名前(任意)
    files/  # role内で使用するファイルを配置
      Rand-Read-4k.fio
      Rand-ReadWrite-4k.fio
      Rand-Write-4k.fio
    tasks/ # roleで実行されるtaskの定義
      main.yml
    vars/  # role内で使用する変数定義
      main.yml
site.yml  # Vagrantから呼ばれるPlaybook
Vagrantfile

4.2.2 最初に呼ばれるPlaybook

Vagrantfileの中の ansible.playbook に指定したPlaybookが最初に実行されます。今回の例では Vagrantfileと同じ階層にある site.yaml という名前のPlaybookです。 このPlaybookの中では、iops というRoleを呼び出しています。

---
- hosts: servers
  become: true
  roles:
    - iops

4.2.3 RoleごとのPlaybook (tasks/main.yml)

site.yaml から呼び出されるPlaybookです。
今回はIOPSテストを行うため、以下の作業を実施します。

  • fioをインストール
  • fioの計測パラメータファイルをリモートに送信
  • fioを実行
  • 結果ファイルを受信
---
    - name: install epel 
      yum: 
        name: epel-release 
        state: installed
    - name: install fio
      yum: 
        name: fio 
        state: installed
      
    - name: copy Rand-Read-4k.fio
      copy: 
        src: Rand-Read-4k.fio
        dest: "{{ dest_dir }}"
    - name: copy Rand-ReadWrite-4k.fio
      copy: 
        src: Rand-ReadWrite-4k.fio
        dest: "{{ dest_dir }}"
    - name: copy Rand-Write-4k.fio
      copy: 
        src: Rand-Write-4k.fio
        dest: "{{ dest_dir }}"

    - name: run fio Rand-Read-4k
      command: "fio -f /tmp/Rand-Read-4k.fio -filename=/tmp/fio_test -output Rand-Read-4k.result"
    - name: run fio Rand-ReadWrite-4k
      command: "fio -f /tmp/Rand-ReadWrite-4k.fio -filename=/tmp/fio_test -output Rand-ReadWrite-4k.result"
    - name: run fio Rand-Write-4k
      command: "fio -f /tmp/Rand-ReadWrite-4k.fio -filename=/tmp/fio_test -output Rand-Write-4k.result"

    - name: search files
      find: 
        paths: "/root"
        patterns: "*.result"   
      register: files_to_copy

    - name: receive result
      fetch:
        src: "{{ item.path }}"
        dest: "{{ receive_dir }}"
        flat: yes
      with_items: "{{ files_to_copy.files }}"

4.2.4 変数定義(vars/main.yml)

RoleごとのPlaybookで使用する変数を定義します。

dest_dir: /tmp/
receive_dir: ./results/

4.2.5 Playbookの確認テスト

これでAnsibleの設定は終了なので、間違いがないか確認しておきましょう。

■ Playbookの構文をチェック:
ansibleコマンドに「–syntax-check」オプションをつけて実行すると、Playbookの構文をチェックできます。

$ ansible-playbook site.yml --syntax-check

■ Dry Run:
ansibleコマンドに「–check」オプションをつけて実行すると、対象への変更は行わずに、Playbookを適用した結果起きる変化を確認できます。

$ ansible-playbook site.yml --check

■ 冗長モード:
もしインスタンスを起動した状態であれば、以下のようにAnsible単独で実行して確認することも可能です。ansibleコマンドに「-v(–verbose)」 オプションをつけて実行すると、詳細な出力を確認することができます。「-vvv」と指定すると、さらに詳細な出力になります。

$ ansible-playbook -i hosts site.yml --private-key=~/.ssh/id_rsa -u root -v

なお、前述のVagrantfile内のAnsibleの呼び出し部分でansible.verbose = trueとすると、冗長モードを指定したことになります。

■ ansible-lint:
Ansibleの機能ではありませんが、Playbookのチェックをしてくれるツールです。別途インストールが必要ですが、Playbookの改善点も指摘してくれます。
下記のように使います。

$ ansible-lint site.yml

参考:
Ansible:さらにPlaybookをきわめる
Ansible公式:Check Mode (“Dry Run”)
GitHub - willthames/ansible-lint: Best practices checker for Ansible

5. 実行

さあ、Vagrantから実行してみましょう。
Vagrantfile のある場所に移動して以下のコマンドを実行します。

$ vagrant up

4.2.4の変数定義で receive_dir に指定した場所に、結果ファイルが入っていれば成功です。

おまけ.Vagrantの基本コマンド

  • 起動: $ vagrant up
  • 停止: $ vagrant halt
  • 削除: $ vagrant destroy
  • 再読込: $ vagrant reload  ※–provisonでプロビジョニングも実施
  • プロビジョンだけ実施: $ vagrant provision