読者です 読者をやめる 読者になる 読者になる

Vagrantで作成した仮想マシンのディスクを後から拡張する方法メモ - CentOS7編

develop

参考にした手順

こちら https://gist.github.com/christopher-hopper/9755310 に記載されている手順が参考になった。ただし、今回利用したCentOS7のvagrant boxのイメージでは、ファイルシステムがCentOS7のデフォルトであるxfsとなっているため、最後のファイル拡張時には xfs_growf コマンドを利用する。

Vagrant使いなら、おそらくVagrantfile内でかっこよく処理して、最初から任意のサイズのディスクで仮想マシンを構成するんだろうが、ぼくはその方法を探せなかった。

vagrant boxをダウンロードする

vagrant boxは、A list of base boxes for Vagrant - Vagrantbox.es から CentOS-7.1.1503-x86_64-netboot.boxをダウンロードして利用した。

$ vagrant box add centos7 https://github.com/holms/vagrant-centos7-box/releases/download/7.1.1503.001/CentOS-7.1.1503-x86_64-netboot.box
$ mkdir ~/vagrant && cd ~/vagrant
$ vagrant box list

vagrant boxから仮想マシンインスタンスを起動させる。

$ vagrant init centos7
$ vagrant up

vagrant boxのディスク構成

今どきだとディスク容量が約10GBというのは小さい。これは、後から変更することを想定しているんだろうが、最初から変更できる方法は、あるのかもしれないが見つけられなかった。

やりたいこと

仮想マシンのディスクを、任意のサイズに変更したい。デフォルトの構成は以下の通り。

  • controller: SATA
  • filename: box-disk1.vmdk
  • size: 9.90GB

起動したvagrant boxにログインして、実際に確認してみる。

[vagrant@localhost ~]$ sudo fdisk -l

Disk /dev/sda: 10.6 GB, 10632560640 bytes, 20766720 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト
Disk label type: dos
ディスク識別子: 0x000a56e0

デバイス ブート      始点        終点     ブロック   Id  システム
/dev/sda1   *        2048     1026047      512000   83  Linux
/dev/sda2         1026048    20766719     9870336   8e  Linux LVM

Disk /dev/mapper/centos-root: 8996 MB, 8996782080 bytes, 17571840 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト


Disk /dev/mapper/centos-swap: 1065 MB, 1065353216 bytes, 2080768 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト

これを拡張する。

ディスク拡張の流れ

仮想マシンのディスクを拡張する作業の流れは以下の通り。

  1. 仮想マシンをシャットダウンする
  2. ディスクのクローン機能を利用してディスクフォーマットをVMDK(box-disk1.vmdk)からVDI形式(box-disk1.vdi)に変更したディスクを作成する
  3. クローンで作成したVDI形式のディスクをリサイズする
  4. リサイズしたディスク(box-disk1.vdi)に切り替える
  5. 仮想マシンを起動する
  6. 拡張されたディスクにパーティションを追加する
  7. 仮想マシンを再起動する
  8. LVMを利用して、VolumeGroupに追加したパーティションを追加する
  9. ルートファイルシステム用の論理ボリューム領域を拡張する
  10. xfsファイルシステムを拡張する

では、実際に拡張してみる。まずは仮想マシンを停止する。

$ vagrant halt
==> default: Attempting graceful shutdown of VM...

続いて、仮想マシンの実体があるディレクトリに移動する。

$ cd ~/VirtualBox\ VMs/test_default_1433612417803_41795
$ ll
total 2759840
drwx------  3 foo  staff   102B  6  7 02:40 Logs
-rw-------  1 foo  staff   1.3G  6  7 02:49 box-disk1.vmdk
-rw-------  1 foo  staff   7.9K  6  7 02:40 test_default_1433612417803_41795.vbox
-rw-------  1 foo  staff   7.9K  6  7 02:40 test_default_1433612417803_41795.vbox-prev

続いて、VBoxManageコマンドを利用して、box-disk1.vmdkをVDI形式でクローンする。

$ VBoxManage clonehd box-disk1.vmdk box-disk1.vdi --format VDI
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Clone hard disk created in format 'VDI'. UUID: 89464f0b-0fa1-49bd-8fd5-ec8105ab6d26

クローンしたファイルを確認する。まだ拡張していないので、サイズは約10GBのまま。

$ VBoxManage showhdinfo box-disk1.vdi
UUID:           89464f0b-0fa1-49bd-8fd5-ec8105ab6d26
Parent UUID:    base
State:          created
Type:           normal (base)
Location:       /Users/foo/VirtualBox VMs/test_default_1433612417803_41795/box-disk1.vdi
Storage format: VDI
Format variant: dynamic default
Capacity:       10140 MBytes
Size on disk:   1369 MBytes

VDIファイル(box-disk1.vdi)をリサイズする。サイズの単位はMB。ここでは30GBに変更する。

$ VBoxManage modifyhd box-disk1.vdi --resize 30720
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%

サイズが変更されたことを確認する。

$ VBoxManage showhdinfo box-disk1.vdi
UUID:           89464f0b-0fa1-49bd-8fd5-ec8105ab6d26
Parent UUID:    base
State:          created
Type:           normal (base)
Location:       /Users/foo/VirtualBox VMs/test_default_1433612417803_41795/box-disk1.vdi
Storage format: VDI
Format variant: dynamic default
Capacity:       30720 MBytes
Size on disk:   1369 MBytes

ディスクをbox-disk1.vmdkからbox-disk1.vdiに切り替える。VBoxManageコマンドを利用して、コントローラ削除->コントローラ追加->ディスク接続という流れで作業を実行する。

$ VBoxManage list vms
"test_default_1433612417803_41795" {dce4105d-4864-48d7-a18e-d60988617beb}
$ VBoxManage storagectl dce4105d-4864-48d7-a18e-d60988617beb --name "SATA Controller" --remove
$ VBoxManage storagectl dce4105d-4864-48d7-a18e-d60988617beb --name "SATA Controller" --add sata
$ VBoxManage storageattach dce4105d-4864-48d7-a18e-d60988617beb --storagectl "SATA Controller" --type hdd --medium box-disk1.vdi --port 0

30GBになっている。続いて仮想マシンを起動する。

$ cd ~/vagrant
$ vagrant up

仮想マシンにログインして、ディスクサイズが30GBになっていることを確認する。

$ vagrant ssh
[vagrant@localhost ~]$ sudo -i
[root@localhost ~]# fdisk -l

Disk /dev/sda: 32.2 GB, 32212254720 bytes, 62914560 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト
Disk label type: dos
ディスク識別子: 0x000a56e0

デバイス ブート      始点        終点     ブロック   Id  システム
/dev/sda1   *        2048     1026047      512000   83  Linux
/dev/sda2         1026048    20766719     9870336   8e  Linux LVM

Disk /dev/mapper/centos-root: 8996 MB, 8996782080 bytes, 17571840 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト


Disk /dev/mapper/centos-swap: 1065 MB, 1065353216 bytes, 2080768 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト

基本パーティション3(TypeはLVM)を作成する。

[root@localhost ~]# fdisk /dev/sda
Welcome to fdisk (util-linux 2.23.2).

Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


コマンド (m でヘルプ): n
Partition type:
   p   primary (2 primary, 0 extended, 2 free)
   e   extended
Select (default p): p
パーティション番号 (3,4, default 3): 3
最初 sector (20766720-62914559, 初期値 20766720):
初期値 20766720 を使います
Last sector, +sectors or +size{K,M,G} (20766720-62914559, 初期値 62914559):
初期値 62914559 を使います
Partition 3 of type Linux and of size 20.1 GiB is set

コマンド (m でヘルプ): t
パーティション番号 (1-3, default 3): 3
Hex code (type L to list all codes): 8e
Changed type of partition 'Linux' to 'Linux LVM'

コマンド (m でヘルプ): p

Disk /dev/sda: 32.2 GB, 32212254720 bytes, 62914560 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト
Disk label type: dos
ディスク識別子: 0x000a56e0

デバイス ブート      始点        終点     ブロック   Id  システム
/dev/sda1   *        2048     1026047      512000   83  Linux
/dev/sda2         1026048    20766719     9870336   8e  Linux LVM
/dev/sda3        20766720    62914559    21073920   8e  Linux LVM

コマンド (m でヘルプ): w
パーティションテーブルは変更されました!

ioctl() を呼び出してパーティションテーブルを再読込みします。

WARNING: Re-reading the partition table failed with error 16: デバイスもしくはリソースがビジー状態です.
The kernel still uses the old table. The new table will be used at
the next reboot or after you run partprobe(8) or kpartx(8)
ディスクを同期しています。

作成したパーティションを利用するには再起動が必要であるため、仮想マシンを再起動する。

[root@localhost ~]# reboot
Connection to 127.0.0.1 closed by remote host.
Connection to 127.0.0.1 closed.


$ vagrant ssh
Last login: Sat Jun  6 18:23:14 2015 from 10.0.2.2
Welcome to your Vagrant-built virtual machine.
[vagrant@localhost ~]$ sudo -i
[root@localhost ~]# pvdisplay
  --- Physical volume ---
  PV Name               /dev/sda2
  VG Name               centos
  PV Size               9.41 GiB / not usable 3.00 MiB
  Allocatable           yes
  PE Size               4.00 MiB
  Total PE              2409
  Free PE               10
  Allocated PE          2399
  PV UUID               5tuLzr-3IXr-pecY-i6yv-JNgy-OeRa-7WrIML

追加した基本パーティション(/dev/sda3)をVolumeGroup(centos)に加える。

[root@localhost ~]# pvcreate /dev/sda3
[root@localhost ~]# pvdisplay
  --- Physical volume ---
  PV Name               /dev/sda2
  VG Name               centos
  PV Size               9.41 GiB / not usable 3.00 MiB
  Allocatable           yes
  PE Size               4.00 MiB
  Total PE              2409
  Free PE               10
  Allocated PE          2399
  PV UUID               5tuLzr-3IXr-pecY-i6yv-JNgy-OeRa-7WrIML

  "/dev/sda3" is a new physical volume of "20.10 GiB"
  --- NEW Physical volume ---
  PV Name               /dev/sda3
  VG Name
  PV Size               20.10 GiB
  Allocatable           NO
  PE Size               0
  Total PE              0
  Free PE               0
  Allocated PE          0
  PV UUID               QotznM-3nYG-nCyj-UUEs-rowi-VFNl-liv55I

[root@localhost ~]# vgextend centos /dev/sda3
  Volume group "centos" successfully extended

ルートファイルシステムを提供している論理ボリュームのデバイス名を確認する。

[root@localhost ~]# df
ファイルシス            1K-ブロック    使用  使用可 使用% マウント位置
/dev/mapper/centos-root     8775680 1063956 7711724   13% /
devtmpfs                     227912       0  227912    0% /dev
tmpfs                        234316       0  234316    0% /dev/shm
tmpfs                        234316    4376  229940    2% /run
tmpfs                        234316       0  234316    0% /sys/fs/cgroup
/dev/sda1                    508588   84776  423812   17% /boot

ルートファイルシステム用の論理ボリュームデバイス( /dev/mapper/centos-root)のサイズを拡張する。

[root@localhost ~]# lvextend -l +100%FREE /dev/mapper/centos-root
  Size of logical volume centos/root changed from 8.38 GiB (2145 extents) to 28.51 GiB (7299 extents).
  Logical volume root successfully resized

この時点では、まだxfsファイルシステムとしては拡張されていない。

[root@localhost ~]# df -h
ファイルシス            サイズ  使用  残り 使用% マウント位置
/dev/mapper/centos-root   8.4G  1.1G  7.4G   13% /
devtmpfs                  223M     0  223M    0% /dev
tmpfs                     229M     0  229M    0% /dev/shm
tmpfs                     229M  4.3M  225M    2% /run
tmpfs                     229M     0  229M    0% /sys/fs/cgroup
/dev/sda1                 497M   83M  414M   17% /boot

最後にxfsファイルシステムを拡張する。

[root@localhost ~]# xfs_growfs /
meta-data=/dev/mapper/centos-root isize=256    agcount=4, agsize=549120 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=0        finobt=0
data     =                       bsize=4096   blocks=2196480, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=0
log      =internal               bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
data blocks changed from 2196480 to 7474176
[root@localhost ~]# df -h
ファイルシス            サイズ  使用  残り 使用% マウント位置
/dev/mapper/centos-root    29G  1.1G   28G    4% /
devtmpfs                  223M     0  223M    0% /dev
tmpfs                     229M     0  229M    0% /dev/shm
tmpfs                     229M  4.3M  225M    2% /run
tmpfs                     229M     0  229M    0% /sys/fs/cgroup
/dev/sda1                 497M   83M  414M   17% /boot

これで完了。 VMDKファイル(box-disk1.vmdk)は、もう使わないと思うので、削除しておいてもいいかも。

devstackを利用したOpenStackの構築 - CentOS7版

OpenStack

CentOS 7にdevstackでOpenStackをインストールしてみたので、手順をメモしておく。

構成

VMware Fusionの上に以下のスペックの仮想マシンを作成する。

  • VMware Fusion Professional 7.1.1 (2498930)
  • cpu: 1
  • mem: 4096MB
  • hdd: 30GB
  • nic0: vmnet10,192.168.100.240/24
  • nic1: vmnet11,172.16.100.240/24

インストール対象コンポーネント

  • cinder
  • heat
  • horizon
  • keystone
  • neutron
  • nova

事前準備

ホスト名の変更や/etc/hostsへの自身のIPアドレスの登録など、基本的な設定を行う。また、VMware Fusion上の仮想マシンNIC名は長すぎて、VLAN & LinuxBridgeの組み合わせのようなケースでは、ipコマンドがインターフェイスを作成するときにエラーとなるので、昔ながらのethNとして利用できるよう、grubの設定を変更しておく。

ホスト名設定(/etc/hostname)

devstack

hostsファイルへの登録(/etc/hosts)

192.168.100.240 devstack
172.16.100.240  devstack

/etc/sysconfig/selinux

「いしかわさんごめんなさい いしかわさんごめんなさい いしかわさんごめんなさい」3回詠唱してから無効化する。

SELINUX=disabled

NetworkManagerを停止する

NetworkManagerを停止して、無効化しておく。

# systemctl stop NetworkManager
# systemctl disable NetworkManager

/etc/sysconfig/network-scripts/ifcfg-eth[01]を作成する

構成にあわせてIPアドレスを設定する

NIC名を従来のethNに戻す(/etc/sysconfig/grub)

  1. /etc/sysconfig/grubGRUB_CMDLINE_LINUX に biosdevname=0 net.ifnames=0 を追記する
  2. grub2-mkconfig -o /boot/grub2/grub コマンドで変更を反映する
  3. システムを再起動する

必要となるパッケージを追加する

個別に必要となるパッケージ群をインストールしておく。Development Toolsはパッケージグループであるため、yum groupinstallでインストールする。

iptablesのクリア

iptablesをクリアした状態で保存しておく。(いらないかも)

# iptables -F
# service iptables save

devstackを利用したOpenStackのインストール

stackユーザを作成してsudoを許可する

ユーザを作成する

# adduser stack
# passwd stack
New password: ********
Retype new password: ********

sudoを許可する

# echo "stack ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

devstackを取得する

公式サイトのリポジトリから、devstackをチェックアウトする。以降の作業はstackユーザで実施する

$ git clone https://git.openstack.org/openstack-dev/devstack
$ cd devstack

local.confを作成する

$HOME/devstack/local.confを作成する

##
## local.conf for devstack
##
[[local|localrc]]
ADMIN_PASSWORD=changeme
MYSQL_PASSWORD=changeme
RABBIT_PASSWORD=changeme
SERVICE_PASSWORD=changeme
SERVICE_TOKEN=changeme

## Log settings
LOGDIR=$DEST/logs
SCREEN_LOGDIR=$LOGDIR
SCREEN_HARDSTATUS="%{= rw} %H %{= wk} %L=%-w%{= bw}%30L> %n%f %t*%{=    wk}%+Lw%-17< %-=%{= gk} %y/%m    /%d %c"
LOGFILE=$LOGDIR/devstack.log

## Milestone of each components
VERSION=master
CINDER_BRANCH=$VERSION
GLANCE_BRANCH=$VERSION
HORIZON_BRANCH=$VERSION
KEYSTONE_BRANCH=$VERSION
NOVA_BRANCH=$VERSION
NEUTRON_BRANCH=$VERSION
SWIFT_BRANCH=$VERSION

## Keystone
KEYSTONE_TOKEN_FORMAT=UUID

## Glance
IMAGE_URLS=http://download.cirros-cloud.net/0.3.2/cirros-0.3.2-x86_64-uec.tar.gz

## Cinder
VOLUME_BACKING_FILE_SIZE=8192M

## Neutron
## To use nova-network, comment out the following
## for VM on VMware Fusion
PRIVATE_NETWORK_NAME=net1
PUBLIC_NETWORK_NAME=ext_net
PUBLIC_NETWORK_GATEWAY=192.168.100.2
FLOATING_RANGE=192.168.100.0/24

Q_PLUGIN=ml2
Q_FLOATING_ALLOCATION_POOL="start=192.168.100.129,end=192.168.100.190"
disable_service n-net
enable_service neutron
enable_service q-svc
enable_service q-agt
enable_service q-dhcp
enable_service q-l3
enable_service q-meta
enable_service q-lbaas
enable_service q-fwaas
enable_service q-vpn


## Heat
enable_service heat h-api h-api-cfn h-api-cw h-eng
#disable_service heat h-api h-api-cfn h-api-cw h-eng

## Ceilometer
#enable_service ceilometer-acompute ceilometer-acentral ceilometer-collector ceilometer-api
disable_service ceilometer-acompute ceilometer-acentral ceilometer-collector ceilometer-api
CEILOMETER_BACKEND=mongo

## Swift
SWIFT_HASH=e2ce2896-d961-4eba-b649-62ae2835f137
#enable_service s-proxy s-object s-container s-account
disable_service s-proxy s-object s-container s-account

## Database backend
enable_service mysql
#enable_service postgresql

##
## [EOF]
##

OpenStackをインストールする

iptablesで母艦からのhorizon及び各APIへのアクセスを許可するスクリプト(open_filter.sh)を作成して実行しておく。

#!/bin/sh
export DEVSTACK_SERVER=192.168.100.240
sudo iptables -A INPUT -p tcp --dport http -j ACCEPT
sudo iptables -I FORWARD 4 -i eth0 -m state --state NEW -m tcp -p tcp -d $DEVSTACK_SERVER --dport http -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 5000 -j ACCEPT
sudo iptables -I FORWARD 4 -i eth0 -m state --state NEW -m tcp -p tcp -d $DEVSTACK_SERVER --dport 5000 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 6080 -j ACCEPT
sudo iptables -I FORWARD 4 -i eth0 -m state --state NEW -m tcp -p tcp -d $DEVSTACK_SERVER --dport 6080 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 8000 -j ACCEPT
sudo iptables -I FORWARD 4 -i eth0 -m state --state NEW -m tcp -p tcp -d $DEVSTACK_SERVER --dport 8000 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 8003 -j ACCEPT
sudo iptables -I FORWARD 4 -i eth0 -m state --state NEW -m tcp -p tcp -d $DEVSTACK_SERVER --dport 8003 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 8004 -j ACCEPT
sudo iptables -I FORWARD 4 -i eth0 -m state --state NEW -m tcp -p tcp -d $DEVSTACK_SERVER --dport 8004 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 8773 -j ACCEPT
sudo iptables -I FORWARD 4 -i eth0 -m state --state NEW -m tcp -p tcp -d $DEVSTACK_SERVER --dport 8773 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 8774 -j ACCEPT
sudo iptables -I FORWARD 4 -i eth0 -m state --state NEW -m tcp -p tcp -d $DEVSTACK_SERVER --dport 8774 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 8775 -j ACCEPT
sudo iptables -I FORWARD 4 -i eth0 -m state --state NEW -m tcp -p tcp -d $DEVSTACK_SERVER --dport 8775 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 8776 -j ACCEPT
sudo iptables -I FORWARD 4 -i eth0 -m state --state NEW -m tcp -p tcp -d $DEVSTACK_SERVER --dport 8776 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 9191 -j ACCEPT
sudo iptables -I FORWARD 4 -i eth0 -m state --state NEW -m tcp -p tcp -d $DEVSTACK_SERVER --dport 9191 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 9292 -j ACCEPT
sudo iptables -I FORWARD 4 -i eth0 -m state --state NEW -m tcp -p tcp -d $DEVSTACK_SERVER --dport 9292 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 9696 -j ACCEPT
sudo iptables -I FORWARD 4 -i eth0 -m state --state NEW -m tcp -p tcp -d $DEVSTACK_SERVER --dport 9696 -j ACCEPT
#
# [EOF]
#

stack.shを実行して、OpenStackをインストールする。stack.sh実行後にscreenでOpenStackの各コンポーネントのサービスが起動するのはubuntu版と同様。

$ cd $HOME/devstack
$ ./stack.sh

再起動時に備えてmariadbhttpdサービスを有効化しておく。

$ sudo systemctl enable mariadb
$ sudo systemctl enable rabbitmq-server
$ sudo systemctl enable httpd
$ sudo systemctl enable openvswitch

リブート後のサービス再開

再起動後にOpenStackの各コンポーネントを起動する方法は以下の通り、cinder-volume用のボリュームバックエンドをlosetupしてからrejoin-stack.shを実行する。あらかじめ、open_filer.shを実行しておくのを忘れずに。

$ sh $HOME/open_filter.sh
$ sudo losetup -f /opt/stack/data/stack-volumes-lvmdriver-1-backing-file
$ cd $HOME/devstack
$ ./rejoin-stack.sh

JenkinsとGerritの連携させてCIっぽい仕組みを作る

ci develop

CI環境

OpenStackのようなCI/CD環境を自前で作りたいと思っていろいろ調べてみたので備忘録として残しておく。使うプロダクトはGerritとJenkinsと、そのバックエンドのMariaDBの3つ。GerritとJenkinsは、ともにJavaVMの上で稼働させる。

  1. Gerrit - ソースコードレビューに利用
  2. Jenkins - ソースコードの自動ビルド&自動チェックに利用

母艦

仮想マシン(CIサーバ)

  • CPU x 1 / Memory 2048MB
  • CentOS Linux release 7.1.1503
  • IPAddress: 10.0.2.10/24
  • java-1.7.0-openjdk-1.7.0.79-2.5.5.1.el7_1.x86_64
  • jenkins-1.596.2-1.1.noarch
  • gerrit-2.10.3.1.war
  • mariadb-server-5.5.41-2.el7_0.x86_64

Jenkins

事前準備

インストールに利用するwgetと、Jenkinsを起動させるためのjdkを、あらかじめインストールしておく。

---
$ sudo yum install wget
$ sudo yum install java-1.7.0-openjdk
---

インストール

JenkinsのRPMパッケージをインストールする。パッケージはCentOS7としては標準提供されていないが、公式サイトが提供しているJenkinsのリポジトリを利用することにより、Jenkins公式RPMパッケージをインストールすることができる。

---
$ sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat-stable/jenkins.repo
$ sudo rpm --import https://jenkins-ci.org/redhat/jenkins-ci.org.key
$ sudo yum install jenkins
---

起動

systemctlコマンドでJenkinsの起動と、OSリブート時の自動起動設定を行う。chkconfigではsystemdのサービス適用外というメッセージが出るが、ここではsystemdのサービスに載せないので気にせず進める。

---
$ chkconfig --list jenkins

Note: This output shows SysV services only and does not include native
      systemd services. SysV configuration data might be overridden by native
      systemd configuration.

      If you want to list systemd services use 'systemctl list-unit-files'.
      To see services enabled on particular target use
      'systemctl list-dependencies [target]'.

jenkins         0:off   1:off   2:off   3:on    4:off   5:on    6:off
---

RPMパッケージをインストールすると、RunLevel:3で自動起動onとなっているので、特になにもしない。続いてサービスを手動で起動する。

---
$ sudo service jenkins start
---

確認

Jenkinsはデフォルト状態で起動させると、ダッシュボードとして0.0.0.0:8080にアクセスすることにより利用できる。

http://10.0.2.0:8080

これで、ひとまずJenkinsが正常にインストールされたことが確認できた。

Gerrit

事前準備

Gerritが利用するデータベースをインストールする

Gerritが利用できるデータベースは、公式サイトのドキュメントによると以下の通り。

ここではMySQL(CentOS7なのでMariaDB)を利用する。

---
$ sudo yum install mariadb
$ sudo yum install mariadb-server
$ sudo systemctl enable mariadb
$ sudo systemctl start mariadb
$ sudo mysqladmin -u root password 'changeme'
---

MariaDBのインストールが完了したら、続いてGerritが利用するデータベースとユーザを作成する。

---
MariaDB [(none)]> CREATE USER 'gerrit2'@'localhost' IDENTIFIED BY 'changeme';
MariaDB [(none)]> CREATE DATABASE reviewdb;
MariaDB [(none)]> GRANT ALL ON reviewdb.* TO 'gerrit2'@'localhost';
MariaDB [(none)]> FLUSH PRIVILEGES;
---

※Gerritを起動させるためにはjdkが必要だが、これはJenkinsのインストール時に既にインストール済みなので割愛。

Gerritユーザ(gerrit2)を作成する

Gerritが利用するユーザアカウント(gerrit2)を作成する。

---
$ sudo adduser gerrit2
---

インストール

Gerritをダウンロードする。

---
$ sudo su - gerrit2
$ wget https://gerrit-releases.storage.googleapis.com/gerrit-2.10.3.1.war
---

起動

ここでは サイト名:review_site のGerritサイトを初期化する。

---
$ java -jar gerrit-2.10.3.1.war init -d /home/gerrit2/review_site

*** Gerrit Code Review 2.10.3.1
***

Create '/home/gerrit2/review_site' [Y/n]? Y

*** Git Repositories
***

Location of Git repositories   [git]:

*** SQL Database
***

Database server type           [h2]: mysql

Gerrit Code Review is not shipped with MySQL Connector/J 5.1.21
**  This library is required for your configuration. **
Download and install it now [Y/n]? Y
Downloading http://repo2.maven.org/maven2/mysql/mysql-connector-java/5.1.21/mysql-connector-java-5.1.21.jar ... OK
Checksum mysql-connector-java-5.1.21.jar OK
Server hostname                [localhost]:10.0.2.10
Server port                    [(mysql default)]:
Database name                  [reviewdb]:
Database username              [gerrit2]:
gerrit2's password             :
              confirm password :

*** Index
***

Type                           [LUCENE/?]:

*** User Authentication
***

Authentication method          [OPENID/?]:

*** Review Labels
***

Install Verified label         [y/N]? y

*** Email Delivery
***

SMTP server hostname           [localhost]:
SMTP server port               [(default)]:
SMTP encryption                [NONE/?]:
SMTP username                  :

*** Container Process
***

Run as                         [gerrit2]:
Java runtime                   [/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.45-30.b13.el7_1.x86_64/jre]:
Copy gerrit-2.10.3.1.war to /home/gerrit2/review_site/bin/gerrit.war [Y/n]? Y
Copying gerrit-2.10.3.1.war to /home/gerrit2/review_site/bin/gerrit.war

*** SSH Daemon
***

Listen on address              [*]:
Listen on port                 [29418]:

Gerrit Code Review is not shipped with Bouncy Castle Crypto SSL v151
  If available, Gerrit can take advantage of features
  in the library, but will also function without it.
Download and install it now [Y/n]? Y
Downloading http://www.bouncycastle.org/download/bcpkix-jdk15on-151.jar ... OK
Checksum bcpkix-jdk15on-151.jar OK

Gerrit Code Review is not shipped with Bouncy Castle Crypto Provider v151
** This library is required by Bouncy Castle Crypto SSL v151. **
Download and install it now [Y/n]? Y
Downloading http://www.bouncycastle.org/download/bcprov-jdk15on-151.jar ... OK
Checksum bcprov-jdk15on-151.jar OK
Generating SSH host key ... rsa... dsa... done

*** HTTP Daemon
***

Behind reverse proxy           [y/N]? N
Use SSL (https://)             [y/N]? N
Listen on address              [*]:
Listen on port                 [8080]: 8081
Canonical URL                  http://localhost:8081/: http://10.0.2.10:8081

*** Plugins
***

Install plugin commit-message-length-validator version v2.10.3.1 [y/N]? y
Install plugin download-commands version v2.10.3.1 [y/N]? y
Install plugin replication version v2.10.3.1 [y/N]? y
Install plugin reviewnotes version v2.10.3.1 [y/N]? y
Install plugin singleusergroup version v2.10.3.1 [y/N]? y

Initialized /home/gerrit2/review_site
...
---

Gerritがデフォルトで開くポートは8080で、Jenkinsが利用しているポートとバッティングする。そこで、GerritをPort:8081で起動するよう明示的に指定してGerritを起動させることにした。

ちなみに、サービスの起動・停止・再起動はサイト(review_site)以下にインストールされている bin/gerrit.sh スクリプトを利用して行う。

---
/home/gerrit2/review_site/bin/gerrit.sh stop|start|restart
---

最後に自動起動設定を行う。gerrit.shはchkconfigコマンドに対応した記述となっている。

---
$ exit    # gerrit2ユーザからexitする
$ ln -snf /home/gerrit2/review_site/bin/gerrit.sh /etc/init.d/gerrit
# sudo -i
# chkconfig --add gerrit
# echo "GERRIT_SITE=/home/gerrit2/review_site" > /etc/default/gerritcodereview
---

確認

Webプラウザで、GerritサーバのPort:8081にアクセスすると、Gerritのダッシュボードを利用することができる。ログインアカウントはLaunchpadアカウント(母艦上で利用しているユーザの公開鍵登録済み)を利用した。

http://10.0.2.0:8081

これで、Gerritも正常にインストールされたことが確認できた。

プロジェクト登録

Gerritのインストールが完了したところで、テスト用のプロジェクト「sandbox」を作成して、Gerritが正しく機能提供できているかをチェックする。

  1. Gerritダッシュボード -> Sign In -> Sign in with a Launchpad ID -> Launchpadアカウントでログインする
  2. settings -> profile -> Usernameを設定する -> SSH Public Keys -> 公開鍵を登録する -> HTTP Password -> Generate Passwordでパスワードを生成する

これでGerritにログインしてプロジェクトを作成することが可能となったので、実際にsandboxプロジェクトを作成してみる

---
$ ssh -p 29418 foo@10.0.2.10 gerrit create-project --empty-commit --name sandbox
---

エラーが出なければ作成成功。Gerritのダッシュボードから確認すると、sandboxプロジェクトが作成されているのがわかる。

続いて、母艦(osx)上で、gitコマンドでGerritのサイトからソースコードをチェックアウトしてみる。

---
$ git clone http://10.0.2.10:8081/sandbox
$ cd sandbox
$ git config --local user.name foo
$ git config --local user.email foo@example.com

$ git remote add gerrit http://10.0.2.10:8081/sandbox
$ git-review -s

$ git branch test/0
$ git checkout test/0
$ date > testfile.txt
$ git add testfile.txt
$ git commit
$ git-review
Username for 'http://10.0.2.10:8081': プロジェクト登録で指定したUsername
Password for 'http://foo@10.0.2.10:8081': プロジェクト登録で生成したHTTP Password
---

おまけ

デフォルトのプロジェクト設定ファイル(project.config)を変更したい場合

---
$ git init cfg ; cd cfg
$ git remote add origin ssh://foo@10.0.2.10:29418/All-Projects
$ git pull origin refs/meta/config
$ vi project.config
$ git push origin HEAD:refs/meta/config
---

いろいろあってパッチセットをDBから削除したい

---
MariaDB [(none)]> use reviewdb
MariaDB [reviewdb]> delete from patch_sets;
---

JenkinsとGerritの連携

事前準備

JenkinsがGerritを利用するために必要になる公開鍵を作成する。パスフレーズありだとテストが成功しないため、ここではパスフレーズ無しの公開鍵を生成した。生成した公開鍵は、あらかじめクライアントに登録しておく。

---
$ sudo -u jenkins ssh-keygen -t rsa -C foo@example.com
---

続いて、母艦(osx)から、GerritにJenkinsのユーザアカウントを登録する。ここでは、アカウント名:jenkinsとした。生成した公開鍵の登録も忘れずに。

---
$ ssh -p 29418 foo@10.0.2.10 gerrit create-account jenkins --email foo@example.com --full-name jenkins
$ cat /tmp/jenkins.pub | ssh -p 29418 foo@10.0.2.10 gerrit set-account jenkins --add-ssh-key -
---

続いて、CIサーバからjenkinsユーザでGerritにログインできることを確認する。Welcomeメッセージが表示されれば、公開鍵の登録は無事に完了している。

---
sudo -u jenkins ssh jenkins@localhost -p 29418
---

Gerrit上でJenkinsのユーザアカウントに対して、コードレビューに必要な権限を設定する。

  1. AdministratorグループのアカウントでGerritにログイン
  2. People -> List Groups -> Non-Interactive Users -> Members を選択する
  3. jenkins ユーザをAddする
  4. Projects -> List -> sandbox -> Access -> Edit -> Add Reference を押す
  5. Reference: refs/* を設定する
  6. Reference: refs/* で Add Permissions -> Read -> ALLOW: Non-Interactive Users を選択する
  7. Reference: refs/heads/* で Label Code-Review に Non-Interactive Users を(-1,+1)で追加する
  8. Reference: refs/heads/* で Label Verified に Non-Interactive Users を(-1,+1)で追加する
  9. People -> Create New Group : "Event Streaming Users" を作成して jenkins ユーザを追加する
  10. Projects -> List -> All-Projects -> Access -> Edit -> Global Capabilities -> Stream Events に ALLOW: Event Streaming Users を追加する

Jenkinsプラグインのインストール

Jenkinsのダッシュボードのプラグインの管理から、Gerrit Trigger PluginとGit Pluginをインストールする。

Gerrit Triggerプラグインの設定

プラグイン管理->Gerritトリガー を選択して、以下の3つのセクションの設定を行う。設定を保存するのを忘れずに。

  1. 新しいサーバを追加
  2. Gerrit接続設定
  3. Gerritレポートスコア

新しいサーバを追加

---
- サーバを追加: develop
- ◉ Gerrit Server with Default Configurations
---

Gerrit接続設定

---
- 名前: develop
- 起動時に接続しない: □
- ホスト名: 10.0.2.10
- フロントエンドURL: http://10.0.2.10:8081/
- SSHポート: 29418
- プロキシ: 空
- ユーザー名: jenkins
- メールアドレス: foo@example.com
- SSHキーファイル: /var/lib/jenkins/.ssh/id_rsa
- SSHキーファイルパスワード: 空
- 最新のパッチのみビルド: □
---

Gerritレポートスコア

---
Verified
  ===
  - 開始: 0
  - 成功: 1
  - 失敗: -1
  - 不安定: 0
  - ビルドせず: 0
  ===

Code-Review
  ===
  - 開始: 0
  - 成功: 1
  - 失敗: -1
  - 不安定: 0
  - ビルドせず: 0
  ===
---

JenkinsとGerritを連携させるジョブの作成

Jenkinsのダッシュボードから、新規ジョブの作成を選択する。

---
プロジェクト名: sandbox_gerrit
説明: Gerritのサンプルプロジェクト用のテストジョブ
フリースタイルジョブ
□ 古いビルドの破棄    Help for feature: 古いビルドの破棄
□ ビルドのパラメータ化  Help for feature: ビルドのパラメータ化
□ ビルド無効化 (プロジェクトが再び有効化されるまで新しいビルドは行われなくなります)
□ ビルドを並行実行
---

ソースコード管理

---
○ なし 
○ CVSCVS Projectset 
◉ Git
   ===
   Repositories
   - Repository URL: git+ssh://jenkins@10.0.2.10:29418/sandbox.git
   - Credentials: なし
   - 高度な設定:
     - Name: 空
     - Refspec: $GERRIT_REFSPEC

   Branches to build
   - Branch Specifier (blank for 'any'): 空   .....空文字にしても、設定を反映すると結局は"**"が入る

   リポジトリ・ブラウザ: 自動

   Additional Behaviours: Strategy for choosing what to build
   - Choosing strategy: Gerritトリガー
   ===
○ Subversion
---

ビルド・トリガ

---
□ Build after other projects are built
■ Gerritイベント
---

Gerritトリガー

トリガーするGerritイベントに、必要なイベントを追加していくが、Patchset Createdだけで十分かな。

---
サーバー: develop
サイレントモード: □
レビューされていないパッチセットをチェックする: ■
トリガーするGerritイベント
  ===
  - Patchset Created
    - Draftsを除外する: □
    - Trivial Rebaseを除外する: □
    - No Code Changeを除外する: □
  ===
動的トリガー設定: □

プロジェクト追加
  ===
  Gerritプロジェクト
  - タイプ: Plain
  - パターン: sandbox
  - ブランチ追加
    ===
    タイプ: Path
    パターン: **
    ===

□ SCMをポーリング
□ 定期的に実行
---

ビルド

ビルド手順を追加する。テスト用なので、成功させたいときは exit 0 で、失敗させたいときは exit 0以外 とする。

---
シェルの実行
  - シェルスクリプト
    ===
    #!/bin/sh
    echo "Jenkins review is done"
    exit 0
    ===
---

おわり

これで、ソースコードをcloneしてソースコードを修正後にcommitし、git-reviewにかけるとパッチセットが作成されて、Gerrit上でレビューが実施できる状態となり、そのタイミングでパッチセットの自動ビルドとチェックをJeninsを利用して実施できる環境を構築できた。

ビルド後の処理

特に何もしない

参考URL

クリスマスの夜はOpenStackをPythonワンライナーでキメる(第1夜)

みなさんめりーくりすます!

この記事は、OpenStack Advent Calendar 2014の12/25の記事です。

日本OpenStackユーザ会のAdvent Calendarでは、第1回からクリスマス(またはイヴ)の夜はOpenStackをワンライナーで操作するという伝統芸をお送りしています。 2014年は4部くらいの構成でお送りする予定で、今日は、その第1夜です(今日は、まだワンライナーじゃないよ)

※決して2013年のワンライナーを解読するのに時間がかかって、締切に間に合わなそうだから、苦しまぎれに4回構成にしたってわけではありません

目標

今回の目標は、ワンライナー仮想マシンのリストを取得するまでです。毎年こんなんですが、、、

PythonのプログラムからOpenStackを操作する方法

ぼくも、正直普段は1の方法で利用しています。2の方法をとるのは、毎年このAdvent Calendarを書くときだけです(^^;

方法1. OpenStackのPythonクライアントライブラリを利用する

方法2. 直接REST APIを叩く

REST APIを利用するためのドキュメント

以下のドキュメント(本当によく書いてあるなぁ)を参考に実装していきます。

普通に書いてみる

python-novaclientを利用しない時点で、すでにあまり普通ではないのですが、まぁ普通に書いてみます。

novaが管理する仮想マシンのリストを取得する手順

OpenStackのREST APIを利用します。基本的にPythonが標準で提供しているライブラリのみで乗り切ります。

1. keystoneに認証してもらってトークンIDとサービスカタログを取得する

サービスカタログには、コンポーネントのエンドポイントURLが - POSTメソッド - URL: $OS_AUTH_URL/tokens - ヘッダ

Content-Type: application/json
Accept: application/json
  • リクエスト(JSON形式)
{
    "auth": {
        "tenantName": $OS_TENANT_NAME,
        "passwordCredentials": {
            "username": $OS_USERNAME,
            "password": $OS_PASSWORD
        }
    }
}
  • レスポンス
{
    "access": {
        "token": {
            ... 省略 ...
            "id": "aaaaa-bbbbb-ccccc-dddd",  <-取得したトークンのID
            "tenant": {
                ... 省略 ...
                "id": "fc394f2ab2df4114bde39905f800dc57", <-取得したテナントID
                "name": $OS_TENANT_NAME
            }
        },
    ... 省略 ...
   }
}

2. keystoneからテナントIDを取得する

Content-Type: application/json
Accept: application/json
X-Auth-Token: トークンID  <-1.で取得したトークンID
  • レスポンス(JSON形式)
{
    "tenants": [
        {
            "id": テナントID,
            "name": "tenant-A",
            ...省略...
        },
        {
            "id": テナントID,
            "name": "tenant-B",
            ...省略...
        }
    ],
    "tenants_links": []
}

3. リージョン名とテナントIDからエンドポイントURLを特定する

$OS_REGION_NAMEと2.で取得したテナントIDを利用して1.で取得したサービスカタログから、nova APIのエンドポイントURLを特定します。

4. novaから仮想マシンのリストを取得する

  • GETメソッド
  • URL: novaAPIのエンドポイントURL/servers
  • ヘッダ
Content-Type: application/json
Accept: application/json
X-Auth-Token: トークンID  <-1.で取得したトークンID
  • レスポンス(JSON形式)
だーーーーっとJSON形式で構造化された仮想マシン情報

ソースコード(nova_list.py)

python-novaclientを使わないと、おそろしくめんどくさい...

#!/usr/bin/env python

import json
import re
import urllib
import urllib2
from os import environ as env


def throw_post(url, body, header):
    request = urllib2.Request(url=url,
                              data=json.dumps(body),
                              headers=header)
    return json.loads(urllib2.urlopen(request).read())


def throw_get(url, header):
    request = urllib2.Request(url=url, headers=header)
    return json.loads(urllib2.urlopen(request).read())


def main():
    os_auth_url = env.get('OS_AUTH_URL').rstrip('/')
    os_user = env.get('OS_USERNAME')
    os_passwd = env.get('OS_PASSWORD')
    os_region = env.get('OS_REGION_NAME')
    os_tenant = env.get('OS_TENANT_NAME')

    header = {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
    }

    #
    # get auth-token and catalog info
    #
    auth_header = header.copy()
    api_tokens_url = os_auth_url + '/tokens'
    auth_body = dict(auth=dict(tenantName=os_tenant,
                               passwordCredentials=dict(username=os_user,
                                                        password=os_passwd)))
    auth_response = throw_post(api_tokens_url, auth_body, auth_header)
    token_info = auth_response['access']['token']
    catalog_info = auth_response['access']['serviceCatalog']

    #
    # get tenant-id
    #
    tenant_header = header.copy()
    api_tenants_url = os_auth_url + '/tenants'
    tenant_header['X-Auth-Token'] = token_info['id']
    tenant_response = throw_get(api_tenants_url, tenant_header)
    for i in tenant_response['tenants']:
        if i['name'] == os_tenant:
            tenant_id = i['id']

    #
    # get endpoint-url
    #
    for i in catalog_info:
        if i['type'] == 'compute':
            for j in i['endpoints']:
                if j['region'] == os_region and j['tenantId'] == tenant_id:
                    os_nova_url = j['publicURL']

    #
    # get instance list
    #
    servers_header = header.copy()
    servers_header['X-Auth-Token'] = token_info['id']
    api_servers_url = os_nova_url + '/servers'
    servers_response = throw_get(api_servers_url, servers_header)
    for i in servers_response['servers']:
        print '%s %s' % (i['id'], i['name'])


if __name__ == '__main__':
    # usage: python nova_list.py
    # description: get instance-list such as "nova list"
    main()


#
# [EOF]
#

実行してみる

ちゃんとリストは取得できますね。

$ python nova_list.py
4f0a63bb-f79e-4850-ad5f-3156d677940b test-vm00
a4ca06c9-aff5-4363-b5aa-7a85eb18500c test-vm01
6e7c2192-253c-4b6d-94b4-f1ada8a993d8 test-vm02
213299ca-1c13-4b5e-8ce6-bbb30758f340 test-vm03

明日からが本番だぜ!

明日からは、この普通のコードをワンライナーに直して行く予定です。 あんまり期待しないでまっててね。今年のOpenStackのアドカレは、まだまだおわらないぜ!

OpenStack & Ansible Advent Calendar 2014 12-24

Ansible OpenStack

OpenStack & Ansible Advent Calendar 2014 12-24

これは、OpenStack (2枚目) Advent Calendar 2014 と Ansible Advent Calendar 2014 の24日目(クリスマスイヴ!!)の記事です。

OpenStackとAnsibleの、12/24という割と重要な日を同時に担当してしまったので、この2つのキーワードを連携させる内容で書いてみました。

AnsibleからOpenStack上に仮想マシンを作成する

AnsibleではOpenStackを操作するためのモジュール群がいくつか提供されています。 しかしながら、積極的にメンテナンスされているのは、 nova_computeモジュール のみという状態に見えます。 そこで、この記事ではnova_computeモジュールの利用方法を紹介します。

モジュール名 機能
glance_image 仮想マシンイメージの登録・削除
keystone_user プロジェクト/ユーザー/ロールの作成・削除・紐付け
nova_compute 仮想マシンの作成・削除
nova_keypair キーペアの登録・削除
quantum_floating_ip フローティングIPの払い出しと仮想マシンインスタンスへの割り当て
quantum_floating_ip_associate 特定フローティングIPの割り当てと割り当て解除
quantum_network 仮想ネットワークの作成・削除
quantum_router 仮想ルータの作成・削除
quantum_router_gateway 仮想ルータと外部ネットワークセグメントの接続・切断
quantum_router_interface 仮想ルータと仮想ネットワークセグメントの接続・切断
quantum_subnet 仮想ネットワーク内のサブネットの作成・削除

しかしながら、このモジュールは問題含みで本当に限られた環境でしか安全に動作しません。 利用方法を紹介する前に、標準提供されるOpenStack操作関連のモジュールが抱える問題(結構致命傷)を2つ書いておきます。OpenStackの仮想マシン管理にAnsibleを利用したい場合(あるのか?)は、対応しておくことをお勧めします。

<問題1> quantumモジュールとglanceモジュールはマルチリージョン未対応

neutronを操作する全てのモジュール(quantum_*)と、glanceを操作するモジュール(glance_image)はマルチリージョンに対応してません。 Optionでは、Region_nameを指定できますが、実際には利用されておらず、OpenStackのクライアントオブジェクト生成時に渡されていない....

<問題2> nova_computeモジュールがfloating_ipの割り当て時に使用済みアドレスの除外に失敗しています

nova_computeモジュールで仮想マシン新規作成時にfloating_ipを割り当てる際、以下のような動きをします。

本来の動作
  1. floating_ip_poolsを指定すると、払い出し済みの全てのfloating_ipの中から未使用のアドレスを1つを選んで仮想マシンに割り当てる
  2. 未使用のアドレスがなければ、新たに1つfloating_ipを払いだして割り当てる
実際の動作

しかし、実際には、払い出し済みかどうかに関わらず、プール内のすべてのfloating_ipの中から1つを選択して割り当ててしまうのですこれはひどい...

背景

nova_computeモジュールでは、floating_ipが割り当て済みかどうかを、APIから返されるfloating_ipに紐付けられているinstance_idから判断しているのですが、現状のnova apiは、instance_idを空で返してきます。nova_computeモジュールはinstance_idが存在していないため、未使用と判断して、これを仮想マシンへの割り当て候補リストに加えてしまうのです。 ちなみに、HP Public Cloudでは、このnovaの不具合が修正されているので問題ありません。

nova_computeモジュールが持つ致命的な不具合

自前で構築したOpenStack環境だとJuno(2014.2)でもこの不具合を引き当てます。 引き当てるとどうなるかというと、既に他の仮想マシンに割り当てられているfloating_ipが強制的に取り上げられて、新たに作成した仮想マシンに付与してしまいます(novaの仕様)。これは相当やばい。

対策

v1.8系のnova_computeモジュールを使うときは要注意!

対策をちゃんと施したほうが良いです。 Pull Requestしてるんだけど、早くマージしてくれないかなぁ...

実際にnova_computeモジュールを利用してみる

前節の対策はおわすれなく。

必須要件

AnsibleからOpenStackを操作するためには、大きく3つの要件を満たしている必要があります。

  1. OpenStack APIのURL/アカウント/パスワード/テナント名/リージョン名を持っている
  2. OpenStackのPythonクライアントライブラリがインストールされている
  3. nova_computeの不具合に対処済みである

下準備

pythonのvirtualenvを利用して仮想実行環境にAnsibleとOpenStackのクライアントライブラリを閉じ込めます。

1. virtualenv環境構築
$ virtualenv $HOME/advc
New python executable in advc/bin/python
Installing Setuptools..............................................................................................................................................................................................................................done.
Installing Pip.....................................................................................................................................................................................................................................................................................................................................done.
$ source advc/bin/activate
(advc)$
2. Ansibleのインストール

pipを利用してAnsibleをインストールする

(advc)$ pip install jinja2 passlib pycrypto pyyaml
(advc)$ pip install ansible
3. python-novaclientとpython-neutronclientのインストールと環境変数設定

nova_computeモジュールは、python-novaclientが提供するライブラリを利用しているため、利用前にインストールしておく必要があります。

依存関係があるのでpython-keystoneclientもインストールされます。

(advc)$ pip install python-novaclient python-neutronclient
(advc)$ vi openrc
export OS_AUTH_URL=https://認証用URL:ポート/v2.0/
export OS_REGION_NAME=リージョン名
export OS_TENANT_NAME=テナント名
export OS_USERNAME=ユーザ名
export OS_PASSWORD=パスワード
4. nova_computeモジュールの配置
(advc)$ cd $HOME/advc/lib/python2.7/site-packages/ansible/modules/core/cloud/openstack
(advc)$ mv nova_compute.py nova_compute.py.org
(advc)$ wget http://goo.gl/8Vr3QT -O nova_compute.py
5. Ansibleの動作確認
(advc)$ cd $HOME
(advc)$ echo "localhost ansible_connection=local" > ansible_hosts
(advc)$ ansible all -i ansible_hosts -m ping

仮想マシンを作成する

作成に必要な仮想マシンやネットワークの情報は nova コマンドや neutron コマンドで取得しておきましょう!

  • create_vm.yml
---
- hosts: localhost
  tasks:
  - name: ansible_python_interpreter setup
    set_fact: ansible_python_interpreter="{{ lookup('pipe', 'which python') }}"
  - name: create virtual machine instance
    nova_compute:
      state: present
      auth_url: "https://認証URL:ポート/v2.0/"
      region_name: "リージョン名"
      login_tenant_name: "テナント名"
      login_username: "ユーザID"
      login_password: "パスワード"
      availability_zone: "アベイラビリティゾーン名"
      flavor_id: フレーバID
      floating_ip_pools:
      - "パブリックネッーワーク名"
      image_id: "GuestOSイメージID"
      key_name: "キーペア名"
      name: "仮想マシンのホスト名"
      nics:
      - net-id: "内部ネットワークID"
      security_groups: "セキュリティグループ名"

#
# [EOF]
#
  • 実行
(advc)$ ansible-playbook -i ansible_hosts create_vm.yml

PLAY [localhost] **************************************************************

GATHERING FACTS ***************************************************************
ok: [localhost]

TASK: [ansible_python_interpreter setup] **************************************
ok: [localhost]

TASK: [create virtual machine instance] ***************************************
changed: [localhost]

PLAY RECAP ********************************************************************
localhost                  : ok=3    changed=1    unreachable=0    failed=0
  • 作成されたかを確認してみる
(advc)$ nova show test-vm00
+-----------------------------+----------------------------------------------------------+
| Property                    | Value                                                    |
+-----------------------------+----------------------------------------------------------+
| OS-EXT-AZ:availability_zone | アベイラビリティゾーン                                   |
| OS-EXT-STS:power_state      | 1                                                        |
| OS-EXT-STS:task_state       | -                                                        |
| OS-EXT-STS:vm_state         | active                                                   |
| accessIPv4                  |                                                          |
| accessIPv6                  |                                                          |
| config_drive                |                                                          |
| created                     | 2014-12-24T08:52:24Z                                     |
| flavor                      | フレーバ名(フレーバID)                                   |
| hostId                      | 4bd0942b81bcc260be67911e43a43fc91217d78a18e59d32f2bd275b |
| id                          | 4f0a63bb-f79e-4850-ad5f-3156d677940b                     |
| image                       | OSイメージ名 (OSイメージID)                              |
| key_name                    | キーペア名                                               |
| metadata                    | {}                                                       |
| name                        | ホスト名                                                 |
| progress                    | 0                                                        |
| security_groups             | セキュリティグループ名                                   |
| status                      | ACTIVE                                                   |
| tenant_id                   | テナントID                                               |
| updated                     | 2014-12-24T08:52:54Z                                     |
| user_id                     | ユーザID                                                 |
| work-net network            | 10.0.0.23, 15.126.228.53                                 |
+-----------------------------+----------------------------------------------------------+

よし!できた! これを基本にしてvarsなどをうまく利用すれば、novaコマンドを素で叩くよりは楽に仮想マシンが作れそうです!

それではみなさん素敵なクリスマスを!

Eucalyptus Advent Calendar 2014 12-20(昼の部+夜の部)

Eucalyptus

Eucalyptus Advent Calendar 2014(昼の部)

普段は赤いStackに属している、しがないPythonistaの僕ですが、なぜか異様に盛り上がっているEucalyptus Advent Calendar 2014の12/20を担当することになりました。

いま、土曜日のオフィスでこの記事を書いています。同僚がひとり寝ています。起こさないように静かに書こう。

おれのゆーかり初体験

まずはインストール

@giraffeforestgさんが担当した12/2の記事を参考にEucalyptus 4をインストールしてみます。

環境はVMWare Fusion仮想マシンで準備

仮想マシン環境

- 母艦: MacOSX 10.10.1 / VMWare Fusion 7.1.0 (2314774)
- CPU x 4
- MEM 8GB
- NIC x 1
- HDD 100GB

サーバ情報

- OS: CentOS6.6
- hostname: eucalyptus
- networking: eth0:172.16.100.10/24 GW:172.16.100.2

インストール前の準備

1. selinuxの無効化

いしかわさんごめんなさい && いしかわさんごめんなさい && いしかわさんごめんなさい

# sed -i --follow-symlinks -e s/=enforcing/=disabled/ /etc/sysconfig/selinux
# reboot
2. パッケージ更新
# yum update
# reboot
3. 細々した設定
  • /etc/hosts に自身のアドレスを記載(OSG-IPも忘れずに!)
172.16.100.10    eucalyptus OSG-IP

インストール実施

FastStartインストーラの実行
  • Proxyの内側にいる場合は http_proxy の設定を忘れずに!
  • Proxyの内側にいる場合は no_proxy に 127.0.0.1,172.16.100.10,OSG-IP を設定しておくのを忘れずに!
  • /var には 100GB 以上の領域割り当てを推奨されるが、粗食で鍛える方針なので無視する。
  • OSG-IPを/etc/hostsに登録しておくのを忘れずに!
  • インストール自体はchef-soloで実施しているっぽいので、きっと冪等性が担保されているはず。失敗してもやり直せばちゃんと動きそう。 <-だめだったのでスナップショットから戻してもう一回
# bash <(curl -Ls eucalyptus.com/install)
NOTE: if you're running on a laptop, you might want to make sure that
you have turned off sleep/ACPI in your BIOS.  If the laptop goes to sleep,
virtual machines could terminate.

Continue? [Y/n] ※<= Y[Enter]
Y

WARNING: we recommend at least 100G of disk space available
in /var for a Eucalyptus Faststart installation.  Running with
less disk space may result in issues with image and volume
management, and may dramatically reduce the number of instances
your cloud can run simultaneously.

Your free space is: 91G

Continue? [y/N] ※<= Y[Enter]
Y

<...>

Welcome to the Faststart installer!

We're about to turn this system into a single-system Eucalyptus cloud.

Note: it's STRONGLY suggested that you accept the default values where
they are provided, unless you know that the values are incorrect.

What's the physical NIC that will be used for bridging? (eth0) ※<=インタラクション

NIC=eth0

What's the IP address of this host? (172.16.100.10) ※<= [Enter]

IPADDR=172.16.100.10

What's the gateway for this host? (172.16.100.2) ※<= [Enter]

GATEWAY=172.16.100.2

What's the netmask for this host? (255.255.255.0) ※<= [Enter]

NETMASK=255.255.255.0

What's the subnet for this host? (172.16.100.0) ※<= [Enter]

SUBNET=172.16.100.0

You must now specify a range of IP addresses that are free
for Eucalyptus to use.  These IP addresses should not be
taken up by any other machines, and should not be in any
DHCP address pools.  Faststart will split this range into
public and private IP addresses, which will then be used
by Eucalyptus instances.  Please specify a range of at least
10 IP addresses.

What's the first address of your available IP range?
172.16.100.129 ※<= ゲストOS用アドレスレンジの先頭アドレス
What's the last address of your available IP range?
172.16.100.190 ■<= ゲストOS用アドレスレンシの末尾アドレス
OK, IP range is good
Public range will be:   172.16.100.129 - 172.16.100.159
Private range will be   172.16.100.160 - 172.16.100.190

Do you wish to install the optional load balancer and image
management services? This add 10-15 minutes to the installation.
Install additional services? [Y/n] ※<= N[Enter]
N
OK, additional services will not be installed.


[Installing Eucalyptus]

If you want to watch the progress of this installation, you can check the
log file by running the following command in another terminal:

tail -f /var/log/euca-install-12.21.2014-00.10.23.log

Your cloud-in-a-box should be installed in 30-45 minutes. Go have a cup of coffee!


   ( (
    ) )
  ........
  |      |]
  \      /
   ------

   [FATAL] Eucalyptus installation failed
   
   Eucalyptus installation failed. Please consult /var/log/euca-install-12.20.2014-17.53.24.log for details.
   
   Please try to run the installation again. If your installation fails again,
   you can ask the Eucalyptus community for assistance:
   
   https://groups.google.com/a/eucalyptus.com/forum/#!forum/euca-users
   
   Or find us on IRC at irc.freenode.net, on the #eucalyptus channel.

おおおおうぅぅ

インストール時のエラー対応

なんだろうねこりゃ。ちょっと時間かけてやってみようかな。でもいいったい何がなんだかわからねぇ。

これがライムグリーンの洗礼か...(夜の部につづく)

Eucalyptus Advent Calendar 2014(夜の部)

ということで日があらたまったあたりで夜の部開始。 オフィスのProxy配下の牢獄ではなく、自宅のネットワークからテストしてみた。

環境はVMWare Fusion仮想マシンで準備

自前MBA11を使って、仮想マシン環境をVMWare Fusionで構築。

- 母艦: MacOSX 10.10.1 / VMWare Fusion 7.1.0 (2314774)
- CPU x 1
- MEM 5632GB
- NIC x 1
- HDD 128GB

インストール開始

どうもeucalyptus-load-balancer-image-1.1.3-0.90.36.el6のダウンロード(300MBくらいある)で、インストーラが利用しているchef-soloがタイムアウトしてしまう...

そこで、Install additional services? [Y/n]は、あきらめてNにした。

そして!そしてついにインストール成功!おれやった、よはぶかさん!

f:id:pyde:20141221163851p:plain

# bash <(curl -Ls eucalyptus.com/install)
NOTE: if you're running on a laptop, you might want to make sure that
you have turned off sleep/ACPI in your BIOS.  If the laptop goes to sleep,
virtual machines could terminate.

Continue? [Y/n]
^C
[root@eucalyptus ~]# yum search eucaly
読み込んだプラグイン:fastestmirror
Loading mirror speeds from cached hostfile
 * base: ftp.jaist.ac.jp
 * extras: ftp.jaist.ac.jp
 * updates: ftp.jaist.ac.jp
================================= 一致: eucaly =================================
python-boto.noarch : A simple, lightweight interface to Amazon Web Services
[root@eucalyptus ~]# bash <(curl -Ls eucalyptus.com/install)
NOTE: if you're running on a laptop, you might want to make sure that
you have turned off sleep/ACPI in your BIOS.  If the laptop goes to sleep,
virtual machines could terminate.

Continue? [Y/n]
Y

[Precheck] Checking root
[Precheck] OK, running as root

[Precheck] Checking curl version
[Precheck] OK, curl is up to date

パッケージ eucalyptus はインストールされていません。
[Precheck] Checking OS
[Precheck] OK, OS is supported

パッケージ PackageKit はインストールされていません。
パッケージ NetworkManager はインストールされていません。
[Precheck] Checking hardware virtualization
[Precheck] OK, processor supports virtualization

[Precheck] Checking if Chef Client is installed
which: no chef-solo in (/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin)
=====
[INFO] Chef not found. Installing Chef Client


  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 18285  100 18285    0     0   4544      0  0:00:04  0:00:04 --:--:-- 18507
警告: /tmp/install.sh.1176/chef-12.0.3-1.x86_64.rpm: ヘッダ V4 DSA/SHA1 Signature, key ID 83ef826a: NOKEY
[Precheck] OK, Chef Client is installed

[Precheck] Identifying primary network interface
wlan0: error fetching interface information: Device not found
em1: error fetching interface information: Device not found
Active network interface eth0 found
[Precheck] OK, network interfaces checked.

[Precheck] OK, running a full update of the OS. This could take a bit; please wait.
To see the update in progress, run the following command in another terminal:

  tail -f /var/log/euca-install-12.21.2014-15.38.59.log

[Precheck] Package update in progress...
読み込んだプラグイン:fastestmirror
更新処理の設定をしています
Loading mirror speeds from cached hostfile
 * base: ftp.jaist.ac.jp
 * extras: ftp.jaist.ac.jp
 * updates: ftp.jaist.ac.jp
更新と設定されたパッケージがありません。
[Precheck] Precheck successful.


[Prep] Removing old Chef templates
[Prep] Downloading necessary cookbooks
警告: RPMDB は yum 以外で変更されました。
~/cookbooks ~
remote: Counting objects: 3126, done.
remote: Compressing objects: 100% (45/45), done.
remote: Total 3126 (delta 14), reused 2 (delta 0)
Receiving objects: 100% (3126/3126), 573.02 KiB | 228 KiB/s, done.
Resolving deltas: 100% (2068/2068), done.
remote: Counting objects: 1490, done.
remote: Total 1490 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (1490/1490), 312.19 KiB | 173 KiB/s, done.
Resolving deltas: 100% (653/653), done.
remote: Counting objects: 197, done.
remote: Total 197 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (197/197), 31.16 KiB, done.
Resolving deltas: 100% (99/99), done.
remote: Counting objects: 967, done.
remote: Total 967 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (967/967), 204.30 KiB | 181 KiB/s, done.
Resolving deltas: 100% (395/395), done.
~
[Prep] Tarring up cookbooks
=====

Welcome to the Faststart installer!

We're about to turn this system into a single-system Eucalyptus cloud.

Note: it's STRONGLY suggested that you accept the default values where
they are provided, unless you know that the values are incorrect.

What's the physical NIC that will be used for bridging? (eth0)

NIC=eth0

What's the IP address of this host? (172.16.0.10)

IPADDR=172.16.0.10

What's the gateway for this host? (172.16.0.2)

GATEWAY=172.16.0.2

What's the netmask for this host? (255.255.255.0)

NETMASK=255.255.255.0

What's the subnet for this host? (172.16.0.0)

SUBNET=172.16.0.0

You must now specify a range of IP addresses that are free
for Eucalyptus to use.  These IP addresses should not be
taken up by any other machines, and should not be in any
DHCP address pools.  Faststart will split this range into
public and private IP addresses, which will then be used
by Eucalyptus instances.  Please specify a range of at least
10 IP addresses.

What's the first address of your available IP range?
172.16.0.129
What's the last address of your available IP range?
172.16.0.190
OK, IP range is good
  Public range will be:   172.16.0.129 - 172.16.0.159
  Private range will be   172.16.0.160 - 172.16.0.190

Do you wish to install the optional load balancer and image
management services? This add 10-15 minutes to the installation.
Install additional services? [Y/n]
N
OK, additional services will not be installed.



[Installing Eucalyptus]

If you want to watch the progress of this installation, you can check the
log file by running the following command in another terminal:

  tail -f /var/log/euca-install-12.21.2014-15.38.59.log

Your cloud-in-a-box should be installed in 15-20 minutes. Go have a cup of coffee!


   ) )
    ( (
  ........
  |      |]
  \      /
   ------


[Config] Enabling web console
EUARE_URL environment variable is deprecated; use AWS_IAM_URL instead
[Config] Adding ssh and http to default security group
GROUP   default
PERMISSION  default ALLOWS  tcp 22  22  FROM    CIDR    0.0.0.0/0
GROUP   default
PERMISSION  default ALLOWS  tcp 80  80  FROM    CIDR    0.0.0.0/0


[SUCCESS] Eucalyptus installation complete!
Time to install: 0:34:34
To log in to the Management Console, go to:
http://172.16.0.10:8888/

User Credentials:
  * Account: eucalyptus
  * Username: admin
  * Password: password

If you are new to Eucalyptus, we strongly recommend that you run
the Eucalyptus tutorial now:

  cd /root/cookbooks/eucalyptus/faststart/tutorials
  ./master-tutorial.sh

Thanks for installing Eucalyptus!

まとめ

  1. DevStackは偉大である
  2. PackStackも偉大である
  3. つまりOpenStackは偉大である それでは、みなさんよいお年を:)

ANSIBLE_KEEP_REMOTE_FILESをTrueにしてみよう!

Ansible Python

Ansible Meetup in Tokyo 2014.09 - connpassのLT用にANSIBLE_KEEP_REMOTE_FILESをTrueにする話を書いた。

http://www.slideshare.net/h-saito/ansible-meetup-in-tokyo-201409