AnsibleでCloudStackを操作する(応用編:テンプレートのカスタマイズ)

  • 6
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

AnsibleによるCloudStackの基礎編として、前回はホストの作成とプロビジョニング(Nginxのインストール)を行いました。

AnsibleでCloudStackを操作する(基礎編:仮想マシン作成とプロビジョニング) - Qiita

今回は、応用編として既存テンプレートのカスタマイズを行います。
CloudStackモジュールの特長である対応リソース・操作の多さや
複雑な処理が書けることが活きる例ではないかと思います。

使用しているファイルは以下レポジトリにあります。

https://github.com/atsaki/idcf-custom-template

環境

今回は例としてIDCFクラウドを使用します。

テンプレートは環境に依存している部分が大きいので、
他の環境では変更が必要かもしれません。

テンプレート作成の流れ

以下の流れでテンプレートを作成していきます。

  1. 仮想マシン作成
  2. プロビジョニング
  3. 仮想マシンからボリューム作成
  4. ボリューム・ファイルシステムのサイズ変更
  5. ボリューム内の不要ファイル削除
  6. ボリュームからテンプレート作成

環境の準備

Ansible・CloudStackモジュールの準備については基本的に基礎編と同じです。

1つ変更点としてjqをインストールしておきます。
CloudStackモジュールはすでに多くのモジュールをサポートしていますが、未対応のリソース・操作も存在します。これらの未対応のリソース・操作をcsjq を使って実行します。

Dockerを使って環境を用意する場合は以下のDockerfilejq がインストールされたイメージをビルドすることができます。

Dockerfile
FROM python:2.7
RUN pip install cs ansible sshpubkeys
RUN curl -s -o /usr/bin/jq http://stedolan.github.io/jq/download/linux64/jq && \
    chmod +x /usr/bin/jq
RUN mkdir -p /usr/share/ansible && \
    cd /usr/share/ansible && \
    git clone https://github.com/resmo/ansible-cloudstack.git
RUN mkdir -p /etc/ansible ; \
    echo "[defaults]"                                       > /etc/ansible/ansible.cfg; \
    echo "host_key_checking = False"                       >> /etc/ansible/ansible.cfg; \
    echo "library = /usr/share/ansible/ansible-cloudstack" >> /etc/ansible/ansible.cfg

各種設定ファイル

今回使用する設定ファイルについて説明します。

Inventoryファイル

今回の例では、CloudStackのパスワード・SSH鍵設定機能を使えるテンプレートでディスクを拡張したもの(large_diskグループ)とVagrantから使用するためにvagrant ユーザーの設定等を行うテンプレート(vagrant_boxグループ)を作成します。

※今回作成するテンプレートはIDCフロンティアが提供しているVagrant用テンプレートとは別のものです。

それぞれを、CentOS 6.6CentOS 7.1Ubuntu 14.01について作成するので、以下の6つを作成することになります。

名前 OS ディスク(GB) Vagrant用
CentOS66-30G CentOS 6.6 30 No
CentOS71-30G CentOS 7.1 30 No
Ubuntu1401-30G Ubuntu 14.01 30 No
CentOS66-Vagrant-30G CentOS 6.6 30 Yes
CentOS71-Vagrant-30G CentOS 7.1 30 Yes
Ubuntu1401-Vagrant-30G Ubuntu 14.01 30 Yes

Inventoryファイルには、これらのテンプレートに対応するホストを書きます。

hosts
[large_disk]
CentOS66-30G
CentOS71-30G
Ubuntu1401-30G

[vagrant_box]
CentOS66-Vagrant-30G
CentOS71-Vagrant-30G
Ubuntu1401-Vagrant-30G

[cloudstack_template:children]
large_disk
vagrant_box

[cloudstack:children]
cloudstack_template

[all:vars]
ansible_ssh_user=root
ansible_ssh_private_key_file=./ansible_ssh
ansible_python_interpreter=python
cache_dir=./cache

グループ変数

グループ変数はあまり変更ありません。

cloudstackグループの変数には、ゾーンやSSH用のファイアウォール・ポートフォワーディングルールなどの設定を書いています。

group_vars/cloudstack
---

ssh_public_key_file: "./ansible_ssh.pub"
zone_name: "augusta"
network_name: "augusta-network1"
service_offering_name: "light.S1"
template_name: "CentOS 7.1 64-bit"
firewall_rules:
  - { protocol: "tcp", start_port: 22, end_port: 22 }
port_forwarding_rules:
  - { protocol: "tcp", public_port: 22, private_port: 22 }

cloudstack_templateグループの変数には、テンプレート作成時の処理・設定を書いています。

group_vars/cloudstack_template
---

cloudstack_template_remove_root_ssh_files: true
cloudstack_template_remove_root_history_files: true
cloudstack_template_remove_log_files: true
cloudstack_template_is_dynamically_scalable: true
cloudstack_template_password_enabled: true

vagrant_boxグループの変数には、Vagrant用テンプレート作成時の処理・設定を書いています。Vagrantテンプレートではパスワードを固定で設定しているためパスワードリセット機能を無効化しています。

group_vars/vagrant_box
---

cloudstack_template_password_enabled: false

ホスト変数

各テンプレートのベースとなるテンプレートとディスクサイズを指定しています。

例えば、CentOS 6.6 Vagrant用テンプレートの設定は次のようになります。

host_vars/CentOS66-Vagrant-30G
---

template_name: "CentOS 6.6 64-bit"
template_volume_size: 30

Playbook

Playbookは以下のコマンドで実行可能です。

# ローカルにAnsibleがインストールされている場合
$ ansible-playbook -i hosts PLAYBOOK.yml
# Dockerを使用している場合
$ docker run --env-file=.env -v $(pwd):/data -w /data --rm ansible ¥
    ansible-playbook -i hosts PLAYBOOK.yml

仮想マシン作成

仮想マシン作成にはdeploy.yml を使用します。

deploy.yml基礎編で使用したものと同じです。中身についてはレポジトリと基礎編の記事を参照してください。

プロビジョニング

vagrant_box.yml を使用しVagrant Box用の設定を行います。

Vagrant用テンプレートではCloudStackのパスワード・SSH鍵設定機能は
使用しないため無効化しておきます。

vagrant_box.yml
---

- hosts: vagrant_box
  gather_facts: no
  pre_tasks:
    - include: set_ansible_ssh_host.yml
  tasks:
    - name: "vagrantユーザーを追加"
      user:
        name: "vagrant"
        password: "{{ 'vagrant'|password_hash('sha512') }}"

    - name: "rootユーザーのパスワードをvagrantに変更"
      user:
        name: "root"
        password: "{{ 'vagrant'|password_hash('sha512') }}"

    - name: "vagrantユーザーの公開鍵をauthorized_keysに登録"
      authorized_key:
        user: "vagrant"
        key: "https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub"

    - name: "sudoの設定変更"
      copy:
        dest: "/etc/sudoers.d/{{ item }}"
        content: |
          {{ item }} ALL=(ALL) NOPASSWD: ALL
          Defaults:{{ item }} !requiretty
          \n 
      with_items:
        - "root"
        - "vagrant"

    - name: "CloudStackのパスワード、SSH鍵設定機能の無効化"
      service:
        name: "{{ item }}"
        enabled: no
      with_items:
        - cloud-set-guest-sshkey
        - cloud-set-guest-sshkey.service
        - cloud-set-guest-password
        - cloud-set-guest-password.service
      ignore_errors: yes

仮想マシンのテンプレート化

clouudstack_template.yml を使用して仮想マシンをテンプレート化します。
clouudstack_template.yml は先述のテンプレート作成工程のうち以下を行います。

  • 仮想マシンからボリューム作成
  • ボリューム・ファイルシステムのサイズ変更
  • ボリューム内の不要ファイル削除
  • ボリュームからテンプレート作成

仮想マシンからボリューム作成

プロビジョニングした仮想マシンをいったん停止し、ROOTボリュームのスナップショットを取得してスナップショットからボリュームを作成します。

ボリュームスナップショットを扱えるモジュールがまだないため、スナップショットはcs でAPIを直接実行して作成しています。

cloudstack_template.yml
    - name: "ROOTボリュームのスナップショットを作成"
      shell: >
        cs createSnapshot \
          name={{ inventory_hostname }} \
          volumeid={{ (volume.stdout|from_json).id }}
      connection: local

    - name: "スナップショットからテンプレート作成用ボリュームを作成"
      cs_volume:
        zone: "{{ zone_name }}"
        name: "{{ inventory_hostname }}"
        snapshot: "{{ inventory_hostname }}"
      connection: local

ボリューム・ファイルシステムのサイズ変更

ボリュームのサイズ変更はcs_volumeモジュールでsize を変更するだけでできます。

clodustack_template.yml
    - name: "テンプレート作成用ボリュームのサイズ変更"
      cs_volume:
        zone: "{{ zone_name }}"
        name: "{{ inventory_hostname }}"
        size: "{{ template_volume_size }}"
      connection: local

このボリュームを元の仮想マシンにアタッチし、拡張したボリュームに合わせてファイルシステムを拡張します。拡張方法についてはIDCFのエンジニアブログを参考にしました。

IDCFクラウド rootディスクの拡張 | IDCF Engineers' Blog

clodustack_template.yml
    - name: "テンプレート作成用ボリュームをアタッチ"
      cs_volume:
        zone: "{{ zone_name }}"
        name: "{{ inventory_hostname }}"
        vm: "{{ inventory_hostname }}"
        state: attached
      connection: local

    - name: "テンプレート作成用ボリュームのファイルシステムサイズ変更"
      shell: | 
        for f in $(ls /sys/class/scsi_host/)
        do
          echo "- - -" > /sys/class/scsi_host/$f/scan
        done

        echo "2048,,83,*" | sfdisk -uS --force /dev/sdb

        blkid | grep /dev/sdb1 | grep -q xfs
        if [ $? -eq 0 ]
        then
          mkdir -p /mnt/data
          mount -o nouuid /dev/sdb1 /mnt/data
          xfs_growfs /mnt/data
          umount /mnt/data
          rmdir /mnt/data
        else
          e2fsck -fp /dev/sdb1
          resize2fs /dev/sdb1
        fi

ボリューム内の不要ファイル削除

テンプレートからベースにした仮想マシンの情報を消すため、
rootのSSH関連ファイル、ヒストリ、ログを削除します。

clodustack_template.yml
    - name: "テンプレートからrootのssh関連ファイルを削除"
      shell: |
        rm -fv /mnt/data/root/.ssh/*
      when: cloudstack_template_remove_root_ssh_files

    - name: "テンプレートからrootのヒストリファイルを削除"
      shell: |
        rm -fv /mnt/data/root/.*history*
      when: cloudstack_template_remove_root_history_files

    - name: "テンプレートからログファイルを削除"
      shell: |
        find /mnt/data/var/log/ -type f | xargs -I {} sh -c "echo '' > {}"
      when: cloudstack_template_remove_log_files

NICの情報が残らないようにネットワーク関連のファイルも削除しておきます。

clodustack_template.yml
    - name: "テンプレートから不要なネットワーク関連ファイルを削除"
      shell: |
        rm -frv /mnt/data/{{ item }}
      with_items:
        - /etc/udev/rules.d/70-persistent-net.rules
        - /var/lib/NetworkManager/*
        - /var/lib/dhcp/dhclient.*
        - /var/lib/dhclient/*

ボリュームからテンプレート作成

サイズ変更・不要ファイルを削除したボリュームからテンプレートを作成します。

テンプレートの作成もCloudStackモジュールではできなかったので、csで実行しています。

clodustack_template.yml
    - name: "テンプレート作成用ボリュームのスナップショットからテンプレート作成"
      shell: >
        cs createTemplate \
          name="{{ inventory_hostname }}" \
          displaytext="{{ inventory_hostname }}" \
          snapshotid="{{ (snapshot.stdout|from_json).id }}" \
          ostypeid="{{ (original_template.stdout|from_json).ostypeid }}" \
          isdynamicallyscalable="{{ cloudstack_template_is_dynamically_scalable }}" \
          passwordenabled="{{ cloudstack_template_password_enabled }}"
      connection: local

リソースの削除

clean.yml でテンプレート作成に利用したリソースを削除することができます。

Vagrantで作成したテンプレートを使う

作成したテンプレートをVagrantから使用してみます。
使用するにはあらかじめVagrantとvagrant-cloudstack をインストールしておく必要があります。

vagrant-cloudstack は、下記コマンドでインストールできます。

$ vagrant plugin install vagrant-cloudstack

Vagrantfile を用意します。
環境変数VAGRANT_BOXを使ってVagrant用テンプレート、通常のIDCFテンプレート両方に対応できるようになっています。(ログインユーザー・SSH鍵の変更やrequirettyの対策

Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.provider :cloudstack do |cloudstack, override|
    cloudstack.host    = "#{ENV['CLOUDSTACK_HOST']}"
    cloudstack.path    = "#{ENV['CLOUDSTACK_PATH']}"
    cloudstack.port    = "#{ENV['CLOUDSTACK_PORT']}"
    cloudstack.scheme  = "#{ENV['CLOUDSTACK_SCHEME']}"

    cloudstack.api_key    = "#{ENV['CLOUDSTACK_KEY']}"
    cloudstack.secret_key = "#{ENV['CLOUDSTACK_SECRET']}"

    cloudstack.zone_name             = "#{ENV['CLOUDSTACK_ZONE_NAME']}"
    cloudstack.template_name         = "#{ENV['CLOUDSTACK_TEMPLATE_NAME']}"
    cloudstack.service_offering_name = "#{ENV['CLOUDSTACK_SERVICE_OFFERING_NAME']}"

    cloudstack.pf_ip_address   = "#{ENV['CLOUDSTACK_PF_IP_ADDRESS']}"
    override.ssh.host          = "#{ENV['CLOUDSTACK_PF_IP_ADDRESS']}"

    if ENV['VAGRANT_BOX'] == "0"
      override.ssh.username = "root"

      cloudstack.keypair            = "#{ENV['CLOUDSTACK_KEYPAIR']}"
      override.ssh.private_key_path = "#{ENV.fetch('CLOUDSTACK_PRIVATE_KEY_PATH',
                                                   '~/.ssh/id_rsa')}"
      override.ssh.pty = true

      config.vm.synced_folder ".", "/vagrant", type: "rsync",
          rsync__rsync_path: "rsync"
    end

    config.vm.provision "shell", inline: "echo Hello" 
  end
end

CloudStack用の環境変数をセットします。
Docker用に.env ファイルを使っている場合は、.envファイルに環境変数を追記しdirenvで読み込ませると管理・設定が楽です。

$ export CLOUDSTACK_API=<API_KEY>
$ export CLOUDSTACK_SECRET=<SECRET_KEY>
$ export CLOUDSTACK_HOST=compute.jp-east.idcfcloud.com
$ export CLOUDSTACK_PATH=/client/api
$ export CLOUDSTACK_PORT=443
$ export CLOUDSTACK_SCHEME=https
$ export CLOUDSTACK_ZONE_NAME=augusta
$ export CLOUDSTACK_TEMPLATE_NAME=CentOS71-Vagrant-30G
$ export CLOUDSTACK_SERVICE_OFFERING_NAME=light.S1
$ export CLOUDSTACK_PF_IP_ADDRESS=<ポートフォワードを設定するIP>
$ export CLOUDSTACK_KEYPAIR=asasaki
$ export CLOUDSTACK_PRIVATE_KEY_PATH=~/.ssh/id_rsa

vagrant upで仮想マシンが起動します。
CentOS71-30GなどVagrant用の設定をしていないテンプレートを使用する場合は、VAGRANT_BOX=0をつけて実行します。(vagrant up以外でもつけてください。)

# Vagrant用テンプレートでない場合はVAGRANT_BOX=0 vagrant up
$ vagrant up

vagrant up が失敗してしまう場合は、ポートフォワードの設定あたりでCtrl-Zでいったん処理を中断し、起動が完了するまで少し待ってから再開させるとうまくいくようです。

正常に起動したら、vagrant ssh でログインできます。

# Vagrant用テンプレートでない場合はVAGRANT_BOX=0 vagrant ssh
$ vagrant ssh

容量を確認すると30Gに拡張されていることがわかります。

$ vagrant ssh
$ df -h
ファイルシス   サイズ  使用  残り 使用% マウント位置
/dev/sda1         30G  1.2G   29G    4% /
devtmpfs         485M     0  485M    0% /dev
tmpfs            494M     0  494M    0% /dev/shm
tmpfs            494M   13M  481M    3% /run
tmpfs            494M     0  494M    0% /sys/fs/cgroup

仮想マシンが不要になったらvagrant destroy コマンドで削除します。

# Vagrant用テンプレートでない場合はVAGRANT_BOX=0 vagrant destroy
$ vagrant destroy

最後に

CloudStackモジュールは多くのリソース、操作をサポートしているため
ほとんどの処理をモジュールの機能で実現することができます。
足りない部分については今後実装して貢献していきたいと思っています。

この投稿は IDCF Cloud Advent Calendar 201513日目の記事です。