AnsibleによるCloudStackの基礎編として、前回はホストの作成とプロビジョニング(Nginxのインストール)を行いました。
AnsibleでCloudStackを操作する(基礎編:仮想マシン作成とプロビジョニング) - Qiita
今回は、応用編として既存テンプレートのカスタマイズを行います。
CloudStackモジュールの特長である対応リソース・操作の多さや
複雑な処理が書けることが活きる例ではないかと思います。
使用しているファイルは以下レポジトリにあります。
環境
今回は例としてIDCFクラウドを使用します。
テンプレートは環境に依存している部分が大きいので、
他の環境では変更が必要かもしれません。
テンプレート作成の流れ
以下の流れでテンプレートを作成していきます。
- 仮想マシン作成
- プロビジョニング
- 仮想マシンからボリューム作成
- ボリューム・ファイルシステムのサイズ変更
- ボリューム内の不要ファイル削除
- ボリュームからテンプレート作成
環境の準備
Ansible・CloudStackモジュールの準備については基本的に基礎編と同じです。
1つ変更点としてjqをインストールしておきます。
CloudStackモジュールはすでに多くのモジュールをサポートしていますが、未対応のリソース・操作も存在します。これらの未対応のリソース・操作をcs
とjq
を使って実行します。
Dockerを使って環境を用意する場合は以下のDockerfile
でjq
がインストールされたイメージをビルドすることができます。
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.6
、CentOS 7.1
、Ubuntu 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ファイルには、これらのテンプレートに対応するホストを書きます。
[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用のファイアウォール・ポートフォワーディングルールなどの設定を書いています。
---
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
グループの変数には、テンプレート作成時の処理・設定を書いています。
---
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テンプレートではパスワードを固定で設定しているためパスワードリセット機能を無効化しています。
---
cloudstack_template_password_enabled: false
ホスト変数
各テンプレートのベースとなるテンプレートとディスクサイズを指定しています。
例えば、CentOS 6.6 Vagrant用テンプレートの設定は次のようになります。
---
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鍵設定機能は
使用しないため無効化しておきます。
---
- 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を直接実行して作成しています。
- 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
を変更するだけでできます。
- name: "テンプレート作成用ボリュームのサイズ変更"
cs_volume:
zone: "{{ zone_name }}"
name: "{{ inventory_hostname }}"
size: "{{ template_volume_size }}"
connection: local
このボリュームを元の仮想マシンにアタッチし、拡張したボリュームに合わせてファイルシステムを拡張します。拡張方法についてはIDCFのエンジニアブログを参考にしました。
IDCFクラウド rootディスクの拡張 | IDCF Engineers' Blog
- 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関連ファイル、ヒストリ、ログを削除します。
- 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の情報が残らないようにネットワーク関連のファイルも削除しておきます。
- 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
で実行しています。
- 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の対策)
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モジュールは多くのリソース、操作をサポートしているため
ほとんどの処理をモジュールの機能で実現することができます。
足りない部分については今後実装して貢献していきたいと思っています。