VagrantでIDCFクラウド、Cloud n、ALTUSを使ってみる

最近、IDCFクラウド、NTTCom Cloud n、GMOクラウド ALTUSで新サービスのリリース・値下げが相次いで発表されました。
どのサービスも最安のプランが月額500円程度と気軽に試せる価格設定となっています。

* [IDCFクラウド](http://www.idcf.jp/cloud/)
* [クラウド・エヌ](http://www.ntt.com/cloudn/)
* [GMOクラウド](https://www.gmocloud.com/?navi=public)

これらのクラウドはCloudStackというソフトウェアをベースに構築されており、共通のCloudStack APIを使って操作することが可能です。

今回はVagrantからCloudStack上に仮想マシンを作成するための[vagrant-cloudstack](https://github.com/schubergphilis/vagrant-cloudstack)というプラグインを使ってそれぞれのサービス上に仮想マシンを作ってみます。

# 準備

## Vagrantのインストール

[Vagrant](https://www.vagrantup.com)がインストールされていない場合にはインストールしておきます。

## Vagrantプラグインのインストール

###  vagrant-cloudstackのインストール

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

```bash
$ vagrant plugin install vagrant-cloudstack
```

### dotenvのインストール

認証情報などVagrantfileに直接書きたくない情報を別ファイルとするため```dotenv```を使用します。

https://github.com/bkeepers/dotenv

```dotenv``` はVagrantのプラグインでなく普通のgemですがプラグインと同じコマンドでインストールできます。

```bash
$ vagrant plugin install dotenv
```

## cloudmonkeyのインストールと設定

### cloudmonkeyのインストール

設定に必要な情報を取得するため今回は[cloudmonkey](https://cwiki.apache.org/confluence/display/CLOUDSTACK/CloudStack+cloudmonkey+CLI)を使います。

cloudmonkeyはpipでインストールできます。（pipはPythonのパッケージ管理ツールです。）

```bash
$ pip install cloudmonkey
```

今回はバージョン5.2.0で導入されたプロファイル機能を使うので古いバージョンを使っている場合にはアップデートしておきます。（**アップデートすると~/.cloudmonkey/configの書き換えが必要になる場合があるので注意**）

```bash
$ pip install -U cloudmonkey
```

### cloudmonkeyの設定

```~/.cloudmonkey/config``` にそれぞれのクラウドを使うため下記の内容を追加します。（ファイルが存在しない場合には、一度```cloudmonkey```コマンドを実行して抜けると作成されています。）

エンドポイント、apikey, secretkeyの調べ方はそれぞれのドキュメントを参照してください

* [IDCクラウド](http://docs.idcf.jp/cloud/)
* [Cloud n](http://info.cloudn-service.com/document/manuals_jp/)
* [ALTUS](http://support.gmocloud.com/pf/)

```ini
[idcfcloud]                                           
url = https://compute.jp-east.idcfcloud.com/client/api
apikey = <IDCFクラウドのAPIキー>
secretkey = <IDCFクラウドのシークレットキー>
password = 
expires = 600 
timeout = 3600

[cloudn-flat]                                           
url = <cloudn(FLAT)のエンドポイント>
apikey = <cloudnのAPIキー>
secretkey = <cloudnのシークレットキー>
password = 
expires = 600 
timeout = 3600

[cloudn-vpc]                                           
url = <cloudn(VPC)のエンドポイント>
apikey = <cloudnのAPIキー>
secretkey = <cloudnのシークレットキー>
password = 
expires = 600 
timeout = 3600

[altus-basic]                                           
url = https://tky001b.pf.gmocloud.com/client/api/
apikey = <ALTUS BasicのAPIキー>
secretkey = <ALTUS Basicのシークレットキー>
password = 
expires = 600 
timeout = 3600

[altus-isolate]                                           
url = https://tky001i.pf.gmocloud.com/client/api/
apikey = <ALTUS IsolateのAPIキー>
secretkey = <ALTUS Isolateのシークレットキー>
password = 
expires = 600 
timeout = 3600
```

設定が正しく行われているか確認するためゾーン野情報を出力させてみます。
使用するプロファイルは```set profile``` で切り替えることができます。

```bash
$ cloudmonkey set profile idcfcloud
$ cloudmonkey list zones

$ cloudmonkey set profile cloudn-flat
$ cloudmonkey list zones

$ cloudmonkey set profile cloudn-vpc
$ cloudmonkey list zones

$ cloudmonkey set profile altus-basic
$ cloudmonkey list zones

$ cloudmonkey set profile altus-isolate
$ cloudmonkey list zones
```

ゾーンの情報が正しく表示されない場合には、設定が間違っている可能性があります。
また、サービスの利用開始ができていない場合などもあるので、ポータルで仮想マシンを作成できるかなど一度試してみるのが良いです。

## Vagrant用テンプレートの作成

各環境にVagrant用のテンプレートを作成します。

作成方法は以下の記事が詳しいです。Cloudnの記事ですが他の環境でも作成方法は同じです。

[CloudnとVagrantを組み合わせて使う方法](http://iwashi.co/2014/06/24/cloudn-with-vagrant/)

IDCFクラウドにはのVagrant用テンプレートが用意されているので、今回はそれを使用します。
新しいバージョンが使えるようになるとVagrant用のテンプレートも追加されていきます。
[IDC Frontier Engineers' Blog - vagrant-cloudstack用 CentOS 6.5 テンプレート公開](http://www.idcf.jp/blog/cloud/vagrant-cloudstack-2/) 

### SSHの鍵について

SSH鍵として[insucure keypair](https://github.com/mitchellh/vagrant/tree/master/keys)を使用している場合、Vagrant 1.7.0以降では```vagrant up``` 実行時に新規に鍵が生成されinsecure keypairが置換されます。鍵の置換が実行された場合、下記のメッセージが表示されます。

```text
==> default: Waiting for SSH to become available...
    default: 
    default: Vagrant insecure key detected. Vagrant will automatically replace
    default: this with a newly generated keypair for better security.
    default: 
    default: Inserting generated public key within guest...
    default: Removing insecure key from the guest if its present...
    default: Key inserted! Disconnecting and reconnecting using new SSH key...
```

鍵の置換を無効にするには```config.ssh.insert_key=false``` を指定してください（デフォルトは```true``` ）。

[config.ssh - Vagrantfile - Vagrant Documentation](http://docs.vagrantup.com/v2/vagrantfile/ssh_settings.html)

### パスワード、SSH鍵設定サービスの無効化

CloudStackには仮想マシン作成時にパスワード、SSH鍵を設定する機能があります。
パスワードは```cloud-set-guest-password``` 、SSH鍵は```cloud-set-guest-sshkey``` によって設定されます。

```bash
$ chkconfig --list | grep cloud
cloud-set-guest-password	0:off	1:off	2:off	3:off	4:off	5:off	6:off
cloud-set-guest-sshkey	0:off	1:off	2:off	3:off	4:off	5:off	6:off
```

パスワードやSSH鍵を起動時に変更されたくない場合、テンプレートの元となる仮想マシンで、これらのサービスを無効にしてください。（例えば、パスワードまたはinsecure keypairでログインし```config.ssh.insert_key=true``` でSSH鍵の置換を行う場合）

```bash
$ chkconfig cloud-set-guest-password off
$ chkconfig cloud-set-guest-sshkey off
```

CloudStackに登録されているSSH鍵ペアを使用する場合は、```cloud-set-guest-sshkey``` を有効にしておく必要があります。

```bash
$ chkconfig cloud-set-guest-sshkey on
```

### rsyncのインストール

vagrant-cloudstack 1.0.0以降では、作成した仮想マシンにrsyncがインストールされていない場合、自動でインストールするので予めテンプレートにrsyncをインストールしておく必要がなくなりました。
（```vagrant up``` 後に、```yum``` や```apt-get``` でrsyncがインストールできるようになっていることは確認しておく必要があります。）

# CloudStackのネットワークについて

同じCloudStackを基盤としたサービスとはいえ各サービスが採用しているハイパーバイザ、ネットワーク構成などは互いに異なっています。

vagrant-cloudstackで必要な設定項目は採用しているネットワーク構成により異なるため、ここでCloudStackのネットワークについて確認しておきます。

CloudStackのネットワークの詳細はドキュメントを参照してください。
[CloudStack Administration Documentation](http://cloudstack-administration.readthedocs.org)

CloudStackのネットワークはBasicネットワークとAdvancedネットワークの2つに大別されます。それぞれのサービスが採用しているネットワークは以下のようになっています。

|                 |  ネットワーク      | ファイアウォール  |仮想マシンのIP |外部からの接続方法                      |
|:----------------|:--------------|:------------------|:------------|:------------------------------------|
| IDCFクラウド     | Advanced      | 仮想ルータ          |プライベート   |ポート転送、スタティックNAT、ロードバランサ |
| Cloudn (FLAT)   | Basic         | セキュリティグループ |グローバル     |直接                                    |
| Cloudn (VPC)    | VPC           | 仮想ルータ（ACL）   |プライベート   |ポート転送、スタティックNAT              |
| ALTUS(Basic)    | Basic         |セキュリティグループ  |プライベート    | スタティックNAT、ロードバランサ          |
| ALTUS(Isolate) | Advanced      | 仮想ルータ         |プライベート    |ポート転送、スタティックNAT、ロードバランサ |


## Basicネットワーク

Basicネットワークでは各アカウントネットワークは同じセグメントを共有しています。ファイアウォールの機能は仮想マシン毎に設定するセキュリティグループによって提供されます。

仮想マシンに割り当てられるIPがグローバルIPの場合とプライベートIPの場合があります。

### グローバルIPが割り当てられる場合

グローバルIPが割り当てられている場合には、セキュリティグループで仮想マシンへの接続を許可することにより外部から直接仮想マシンへ接続することができます。

```text
     +------------+     
     |  Internet  |     
     +-----+------+     
           | 
     +-----+------+     
     |            |     
     |            |     
+-SG-+---+    +-SG+----+
|        |    |        |
| +----+ |    | +----+ |
| | VM | |    | | VM | |
| +----+ |    | +----+ |
|        |    |        |
+--------+    +--------+
```

### プライベートIPが割り当てられる場合

プライベートIPが割り当てられる場合、外部との間にスタティックNAT・ロードバランサといった機能を提供する機器があります。この機器でスタティックNAT、ロードバランサを設定することにより外部から仮想マシンへ接続できるようになります。

```text
     +------------+     
     |  Internet  |     
     +-----+------+     
           |                      
     +-----+------+     
     |LoadBalancer|     
     |StaticNat   |     
     +-----+------+     
           |            
     +-----+------+     
     |            |     
     |            |     
+-SG-+---+    +-SG+----+
|        |    |        |
| +----+ |    | +----+ |
| | VM | |    | | VM | |
| +----+ |    | +----+ |
|        |    |        |
+--------+    +--------+
```

## Advancedネットワーク

Advancedネットワークでは各アカウントのネットワークはVLANで分離されています。
仮想マシンの上位にある仮想ルータがファイアウォール、ポートフォワーディング、スタティックNAT、ロードバランサの機能を提供しています。
仮想マシンにはプライベートIPが割り当てられるため、外部からの接続にはポートフォワーディング・スタティックNAT・ロードバランサいずれかの設定を行う必要があります。


```text
    +--------+
    |Internet|
    +---+----+
        |
  +-----+-------+
  |VirtualRouter|
  +-----+-------+
        |
  +------------+
  |            |
  |            |
+----+       +----+
| VM |       | VM |
+----+       +----+                                                                                       
```                                                                                                             

## VPC

VPC(Virtual Private Cloud) では、ネットワークを複数のサブネットに分割することができます。外部やサブネット間の通信はACLを用いて制御することができます。

```text
                 +--------+
                 |Internet|
                 +---+----+
                     |
               +-----+-------+
               |VirtualRouter|
               +--+--+---+---+
                  |      |
        +---------+      +--------+
        |                         |
  +-----+------+           +------+-----+
  |            |           |            |
  |            |           |            |
+----+       +----+      +----+       +----+
| VM |       | VM |      | VM |       | VM |
+----+       +----+      +----+       +----+
```

# vagrant-cloudstackで扱えるネットワーク構成について

vagrant-cloudstackを使用するためには作成した仮想マシンにSSHで接続できる必要があります。
（接続できないと作成後に破棄されてしまう。）

vagrant-cloudstackは以下のネットワーク設定を行うことができます。

* セキュリティグループ
* ポートフォワーディング(VPC以外)
* スタティックNAT

VPCでのポートフォワーディング設定が必要となる```Clodudn VPCタイプOpenNW``` では外部からの接続に必要な設定を行うことができません。
※作成する仮想マシンと同一のネットワークからVagrantを実行すればおそらく動きます。

# Vagrantfileの作成

## 基本的なVagrantfile

vagrant-cloudstackを使用する上で基本的なVagrantfileは以下のようになります。

どの環境においても設定すべき項目に大きな違いはありませんが、ネットワークの設定等に若干の違いがあります。

```rb
# .envの内容を読み込み
Dotenv.load

Vagrant.configure("2") do |config| 
  config.vm.provider :cloudstack do |cloudstack, override| 

    # dummy box                        
    override.vm.box = "dummy"       
    override.vm.box_url = "https://github.com/schubergphilis/vagrant-cloudstack/raw/master/dummy.box"
       
    # エンドポイント
    # URLが https://compute.jp-east.idcfcloud.com/client/api の場合 
    cloudstack.host    = "compute.jp-east.idcfcloud.com"
    cloudstack.path    = "/client/api"
    cloudstack.port    = "443"
    cloudstack.scheme  = "https"
    
    # APIキー・シークレットキー
    cloudstack.api_key    = "#{ENV['CLOUDSTACK_API_KEY']}"
    cloudstack.secret_key = "#{ENV['CLOUDSTACK_SECRET_KEY']}"           
    
    # 仮想マシン作成のパラメータ 
    cloudstack.display_name          = "CentOS65"
    cloudstack.zone_name             = "tesla"
    cloudstack.template_name         = "CentOS 6.5 64-bit for Vagrant"
    cloudstack.service_offering_name = "light.S1"                      
    
    # 仮想マシンへの接続に必要なネットワークの設定
    cloudstack.pf_ip_address    = "#{ENV['CLOUDSTACK_PF_IP_ADDRESS']}"           
    cloudstack.pf_public_port   = "#{ENV['CLOUDSTACK_PF_PUBLIC_PORT']}"
    cloudstack.pf_private_port  = "22"
   
    # 仮想マシンへの接続に必要なSSHの設定 
    override.ssh.private_key_path = "#{ENV['VAGRANT_SSH_PRIVATE_KEY']}"
    override.ssh.port             = "#{ENV['CLOUDSTACK_PF_PUBLIC_PORT']}"                                                
  end
end 
```

Vagrantfileと同じディレクトリに下記内容で```.env``` ファイルを作成します。
Vagrantfileで使用する環境変数に合わせて内容は変えてください。

```sh
CLOUDSTACK_API_KEY          = '<APIキー>'
CLOUDSTACK_SECRET_KEY       = '<シークレットキー>'
CLOUDSTACK_PF_IP_ADDRESS    = '<ポートフォワーディングに使用するIPアドレス>'  
CLOUDSTACK_PF_PUBLIC_PORT   = '<ポートフォワーディングに使用するパブリック側のポート番号>'
VAGRANT_SSH_PRIVATE_KEY     = '~/.ssh/id_rsa'   
```

## 設定すべき値の調べ方

エンドポイント・APIキー・シークレットキーについては```cloudmonkey``` の設定内容と同じとなります。調べる方法については各サービスのドキュメントを参照してください。

仮想マシンの作成に必要なパラメータについては名前で指定できるためほとんどの項目についてはGUIから確認可能です。```cloudmonkey``` を使って以下のように調べることも可能です。

```bash
$ cloudmonkey
> set profile idcfcloud
> list zones
> list templates templatefilter=executable
> list serviceofferings
> list networks
```

## 仮想マシンの作成

Vagrantfileと.envがあるディレクトリで下記コマンドを実行すると仮想マシンが作成されます。

```bash
$ vagrant up --provider=cloudstack
```

うまくいかない場合には```--debug``` オプションをつけて実行することで、詳細な情報を表示できます。

```bash
$ vagrant up --provider=cloudstack --debug
```


# 実例

今回はVagrantを実行するマシンが外部にあることを想定して下記のサービスの設定例を示します。

* Advancedネットワーク
  * IDCFクラウド
  * ALTUS (Isolate)
* Basicネットワーク
  * Cloudn (FLAT)
  * ALTUS (Basic)

## Advancedネットワーク

Advancedネットワークを使用する場合には、仮想マシンがグローバルIPをもっていないためポートフォワーディングを設定し外部から接続できるようにします。

設定の際には使用するポートフォワーディングに使用するIPアドレスを取得しidを調べる必要があります。
GUIでも```cloudmonkey``` で次の様に行うことも可能です。

```bash
# IDの確認
$ cloudmonkey list publicipaddresses
# IPの取得
$ cloudmonkey associate ipaddress zoneid=<zone id>
```

また、SSH接続する際にパブリック側で使用するポート番号を決めておきます。

```Vagrantfile``` では下記のようにネットワークの指定とポートフォワーディングの設定を行います。

```rb
    # 仮想マシンへの接続に必要なネットワークの設定                                 
    cloudstack.pf_ip_address    = "#{ENV['CLOUDSTACK_PF_IP_ADDRESS]}"
    cloudstack.pf_public_port   = "#{ENV['CLOUDSTACK_PF_PUBLIC_PORT']}"
    cloudstack.pf_private_port  = "22"
    override.ssh.port           = "#{ENV['CLOUDSTACK_PF_PUBLIC_PORT']}"     
```

```.env``` にはパブリックIPアドレスとパブリック側のポート番号を設定します。

```rb
CLOUDSTACK_PF_IP_ADDRESS = '<ポートフォワーディングに使用するIPアドレス>'
CLOUDSTACK_PF_PUBLIC_PORT   = '<パブリック側のポート>'
```

### IDCFクラウドの場合

IDCFクラウドではCentOSなどいくつかのOSでVagrant用のテンプレートが用意されており、テンプレートの用意の手間を省く事ができます。

#### SSH鍵ペアの生成

仮想マシンにログインするためのSSHの鍵を生成しておきます。
ここでは「sshkeypair」と言う名前で作成しました。

```bash
$ cloudmonkey set profile idcfcloud
$ cloudmonkey create sshkeypair name=sshkey
```

結果としてsshの秘密鍵が返ってくるので、下記の部分をコピーして```~/.ssh/id_rsa_idcfcloud``` に保存しておきます。

```text
-----BEGIN RSA PRIVATE KEY-----
（英数字の羅列）
-----END RSA PRIVATE KEY-----
```

保存したファイルの権限を変えます。

```bash
$ chmod 600 ~/.ssh/id_rsa_idcfcloud
```

#### Vagrantfile

```Vagrantfile``` は下記のようになります。

```rb
Dotenv.load

Vagrant.configure("2") do |config|
  config.vm.provider :cloudstack do |cloudstack, override|

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

    # エンドポイント
    cloudstack.host    = "compute.jp-east.idcfcloud.com"
    cloudstack.path    = "/client/api"
    cloudstack.port    = "443"
    cloudstack.scheme  = "https"

    # APIキー・シークレットキー
    cloudstack.api_key    = "#{ENV['CLOUDSTACK_API_KEY']}"
    cloudstack.secret_key = "#{ENV['CLOUDSTACK_SECRET_KEY']}"

    # 仮想マシン作成のパラメータ
    cloudstack.display_name          = "CentOS65"
    cloudstack.zone_name             = "tesla"
    cloudstack.template_name         = "CentOS 6.5 64-bit for Vagrant"
    cloudstack.service_offering_name = "light.S1"

    # 仮想マシンへの接続に必要なネットワークの設定
    cloudstack.pf_ip_address    = "#{ENV['CLOUDSTACK_PF_IP_ADDRESS']}"
    cloudstack.pf_public_port   = "#{ENV['CLOUDSTACK_PF_PUBLIC_PORT']}"
    cloudstack.pf_private_port  = "22"

    # 仮想マシンへの接続に必要なSSHの設定
    cloudstack.keypair            = "#{ENV['CLOUDSTACK_SSH_KEYPAIR']}"
    override.ssh.private_key_path = "#{ENV['VAGRANT_SSH_PRIVATE_KEY']}"
    override.ssh.port             = "#{ENV['CLOUDSTACK_PF_PUBLIC_PORT']}"
  end
end
```

.envファイルは下記のようになります。

```rb
CLOUDSTACK_API_KEY          = '<APIキー>'
CLOUDSTACK_SECRET_KEY       = '<シークレットキー>'
CLOUDSTACK_PF_IP_ADDRESS 　　= '<パブリックIPアドレス>'
CLOUDSTACK_PF_PUBLIC_PORT   = '2222'
CLOUDSTACK_SSH_KEYPAIR      = 'sshkeypair'
VAGRANT_SSH_PRIVATE_KEY     = '~/.ssh/id_rsa_idcfcloud'
```

### ALTUS(Isolate)の場合

#### ネットワークの作成とIPアドレスの取得

ALTUS(Isolate)の場合には、まず外部に出るためのネットワークを作成とIPアドレスの取得を行います。方法はドキュメントにしたがってください。

```cloudmonkey``` で次のように行うこともできます。

```bash
$ cloudmonkey set profile altus-isolate
# zoneのidを調べる
$ cloudmonkey list zones
# 作成したい仮想ルータのスペック(VRS, VRM, VRL)のnetworkofferingのidを調べる
# 次のようにnameなどでフィルターすると多少は楽
$ cloudmonkey list networkofferings name=VRS
# ネットワークの作成
$ cloudmonkey create network name=network1 displaytext=network1 zoneid=<zoneid> networkofferingid=<networkofferingid>
# IPアドレスの取得
$ cloudmonkey associate ipaddress zoneid=<zoneid>
```

ネットワークは課金対象なので不要になったら削除しておきます。
仮想マシンが残っていると(Destroyed状態でも)削除できないのであらかじめ削除しておきます。

```bash
# ネットワークのIDを調べる
$ cloudmonkey list network name=network1
# ネットワークの削除
$ cloudmonkey delete network id=<network id>
```

#### Vagrantfile

```Vagrantfile``` の中身は構成が同じなので当然といえば当然ですがIDCFクラウドとほとんど同じです。違いはテンプレートに固定でSSHの鍵をいれているため、```cloudstack.keypair``` がないことです。

```rb
Dotenv.load

Vagrant.configure("2") do |config|
  config.vm.provider :cloudstack do |cloudstack, override|

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

    # エンドポイント
    cloudstack.host   = "tky001i.pf.gmocloud.com"
    cloudstack.path   = "/client/api"
    cloudstack.port   = "443"
    cloudstack.scheme = "https"

    # APIキー・シークレットキー
    cloudstack.api_key    = "#{ENV['CLOUDSTACK_API_KEY']}"
    cloudstack.secret_key = "#{ENV['CLOUDSTACK_SECRET_KEY']}"

    # 仮想マシン作成のパラメータ
    cloudstack.display_name          = "CentOS65"
    cloudstack.zone_name             = "Isolate_tky001"
    cloudstack.template_name         = "CentOSVagrant"
    cloudstack.service_offering_name = "XSV(1 vCPU / 0.5GB RAM)"

    # 仮想マシンへの接続に必要なネットワークの設定
    cloudstack.pf_ip_address    = "#{ENV['CLOUDSTACK_PF_IP_ADDRESS']}"
    cloudstack.pf_public_port   = "#{ENV['CLOUDSTACK_PF_PUBLIC_PORT']}"
    cloudstack.pf_private_port  = "22"

    # 仮想マシンへの接続に必要なSSHの設定
    override.ssh.port             = "#{ENV['CLOUDSTACK_PF_PUBLIC_PORT']}"
  end
end   
```

.envファイルは下記のようになります。

```rb
CLOUDSTACK_API_KEY         = '<APIキー>'
CLOUDSTACK_SECRET_KEY      = '<シークレットキー>'
CLOUDSTACK_PF_IP_ADDRESS   = '<ポートフォワーディングに使用するIPアドレス>'
CLOUDSTACK_PF_PUBLIC_PORT  = '2222'
```

## Basicネットワーク

Basicネットワークではセキュリティグループによって仮想マシンへの接続が制御されています。

Vagrantfileでセキュリティグループを作成することもできますが、今回は事前にSSH接続を許可するセキュリティグループを作成しておきます。

```cloudmonkey``` を使う場合は下記のように作成することができます。

```bash
$ cloudmonkey create securitygroup name=ssh
$ cloudmonkey authorize securitygroupingress securitygroupname=ssh cidrlist=0.0.0.0/0 protocol=tcp startport=22 endport=22
```

```Vagrantfile``` でネットワークの種類と仮想マシンに割り当てるセキュリティグループを設定します。Basicネットワークではネットワーク名を指定する必要はありません。

```rb
    cloudstack.network_type         = "Basic"
    cloudstack.security_group_names = ["ssh"]
```

### Cloud n(FLATタイプ)の場合

Cloud n(FLATタイプ) では仮想マシンがグローバルIPアドレスを持っているので、セキュリティグループの設定のみで外部から接続可能となります。

#### Vagrantfile

```rb
Dotenv.load

Vagrant.configure("2") do |config|
  config.vm.provider :cloudstack do |cloudstack, override|

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

    # エンドポイント
    cloudstack.host   = "comp-api.jp-e1.cloudn-service.com"
    cloudstack.path   = "/client/api"
    cloudstack.port   = "443"
    cloudstack.scheme = "https"

    # APIキー・シークレットキー
    cloudstack.api_key    = "#{ENV['CLOUDSTACK_API_KEY']}"
    cloudstack.secret_key = "#{ENV['CLOUDSTACK_SECRET_KEY']}"

    # 仮想マシン作成のパラメータ
    cloudstack.zone_name             = "jp-e1a"
    cloudstack.template_name         = "CentOS65"
    cloudstack.service_offering_name = "t1.micro"
    cloudstack.network_type          = "Basic"

    # 仮想マシンへの接続に必要なネットワークの設定
    cloudstack.security_group_names = ["ssh"]
  end
end   
```

.envファイルは下記のようになります。

```rb
CLOUDSTACK_API_KEY          = '<APIキー>'
CLOUDSTACK_SECRET_KEY       = '<シークレットキー>'
```

### ALTUS(Basicタイプ)の場合

ALTUS(Basic) では外部からの仮想マシンに接続するためにセキュリティグループの設定に加え、スタティックNATの設定が必要となります。

スタティックNATに使用するIPアドレスは仮想マシン作成前に取得しておく必要があります。取得方法についてはドキュメントを参照してください。
cloudmonkeyでIPアドレスを取得することも可能です。

```bash
$ cloudmonkey associate ipaddress zoneid=<zoneid>
```

#### Vagrantfile

```rb
Dotenv.load

Vagrant.configure("2") do |config|
  config.vm.provider :cloudstack do |cloudstack, override|

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

    # エンドポイント
    cloudstack.host   = "tky001b.pf.gmocloud.com"
    cloudstack.path   = "/client/api"
    cloudstack.port   = "443"
    cloudstack.scheme = "https"

    # APIキー・シークレットキー
    cloudstack.api_key    = "#{ENV['CLOUDSTACK_API_KEY']}"
    cloudstack.secret_key = "#{ENV['CLOUDSTACK_SECRET_KEY']}"

    # 仮想マシン作成のパラメータ
    cloudstack.zone_name             = "Basic_tky001"
    cloudstack.template_name         = "CentOS 6.4 for Vagrant"
    cloudstack.service_offering_name = "Mini Server"
    cloudstack.network_type          = "Basic"

    # 仮想マシンへの接続に必要なネットワークの設定
    cloudstack.security_group_names = ["ssh"]

    # スタティックNATに使用するIPアドレスの指定
    cloudstack.static_nat = [
      {:ipaddress => "#{ENV['PUBLIC_IP_ADDRESS']}"}
    ]
    
    # 仮想マシンへの接続に必要なSSHの設定
    override.ssh.host = "#{ENV['PUBLIC_IP_ADDRESS']}"
  end
end  
```

.envファイルは下記のようになります。

```rb
CLOUDSTACK_API_KEY          = '<APIキー>'
CLOUDSTACK_SECRET_KEY       = '<シークレットキー>'
PUBLIC_IP_ADDRESS           = '<スタティックNATに使用するパブリックIP>'
```

# プロビジョニング

```vagrant-cloudstack``` でもプロビジョニング機能を使うことができます。

今回はIDCFクラウドにShell Provisioner で[Mackerel](https://mackerel.io/)のエージェントをインストールしてみます。他のクラウドでも大きな違いはありません。

destroy時にリタイア処理を行うため```vagrant-triggers``` プラグインをインストールしておきます。

```bash
$ vagrant plugin install vagrant-triggers
```

Vagrantfileと.envは以下のようになります。upすると自動でMackerelに登録され、destroy時にリタイアします。（リタイア処理はdestroyの確認前に実行されてしまうので注意）

```rb
Dotenv.load

Vagrant.configure("2") do |config|
  config.vm.provider :cloudstack do |cloudstack, override|

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

    # エンドポイント
    cloudstack.host    = "compute.jp-east.idcfcloud.com"
    cloudstack.path    = "/client/api"
    cloudstack.port    = "443"
    cloudstack.scheme  = "https"

    # APIキー・シークレットキー
    cloudstack.api_key    = "#{ENV['CLOUDSTACK_API_KEY']}"
    cloudstack.secret_key = "#{ENV['CLOUDSTACK_SECRET_KEY']}"

    # 仮想マシン作成のパラメータ
    cloudstack.display_name          = "CentOS65"
    cloudstack.zone_name             = "tesla"
    cloudstack.template_name         = "CentOS 6.5 64-bit for Vagrant"
    cloudstack.service_offering_name = "light.S1"

    # 仮想マシンへの接続に必要なネットワークの設定
    cloudstack.pf_ip_address    = "#{ENV['CLOUDSTACK_PF_IP_ADDRESS']}"
    cloudstack.pf_public_port   = "#{ENV['CLOUDSTACK_PF_PUBLIC_PORT']}"
    cloudstack.pf_private_port  = "22"

    # 仮想マシンへの接続に必要なSSHの設定
    cloudstack.keypair            = "#{ENV['CLOUDSTACK_SSH_KEYPAIR']}"
    override.ssh.private_key_path = "#{ENV['VAGRANT_SSH_PRIVATE_KEY']}"
    override.ssh.port             = "#{ENV['CLOUDSTACK_PF_PUBLIC_PORT']}"
  end

  config.vm.provision :shell do |s|
    s.inline = <<-"EOS"
      rpm -qa | grep -qw mackerel-agent || \
        rpm -ivh http://file.mackerel.io/agent/rpm/mackerel-agent-latest.noarch.rpm
      egrep -qw "^apikey" /etc/mackerel-agent/mackerel-agent.conf || \
        echo 'apikey = "#{ENV['MACKEREL_API_KEY']}"' >> /etc/mackerel-agent/mackerel-agent.conf
      egrep -qw "^roles" /etc/mackerel-agent/mackerel-agent.conf || \
        echo 'roles = #{ENV['MACKEREL_ROLES']}' >> /etc/mackerel-agent/mackerel-agent.conf
      /etc/init.d/mackerel-agent restart
    EOS
  end

  config.trigger.before :destroy do
    run_remote "MACKEREL_HOST_ID=$( cat /var/lib/mackerel-agent/id );\
                curl https://mackerel.io/api/v0/hosts/${MACKEREL_HOST_ID}/retire \
                  -H \"X-Api-Key: #{ENV['MACKEREL_API_KEY']}\" \
                  -H \"Content-Type: application/json\" \
                  -d \"{}\""
  end
end
```

.envファイルは下記のようになります。

```rb
CLOUDSTACK_API_KEY          = '<APIキー>'
CLOUDSTACK_SECRET_KEY       = '<シークレットキー>'
CLOUDSTACK_PF_IP_ADDRESS    = '<ポートフォワーディングに使用するIPアドレス>'
CLOUDSTACK_PF_PUBLIC_PORT   = '2222'
CLOUDSTACK_SSH_KEYPAIR      = 'sshkeypair'
VAGRANT_SSH_PRIVATE_KEY     = '~/.ssh/id_rsa_idcfcloud'
MACKEREL_API_KEY            = '<MackrerelのAPIキー>'
MACKEREL_ROLES              = '["Vagrant:testVM"]'
```

# トラブルシューティング

正常に仮想マシンが作成されない場合には、次のような点を確認・対処します。

* vagrantのメッセージからどこで失敗しているか確認
  * debugオプションを付けると詳細なメッセージが出力されます
  * 仮想マシンの作成後に削除処理が実行されている場合にはSSH接続がうまくいっていません。
    SSH接続が可能になるのを待っているタイミングでCtrl-zで処理を一時的に停止すると調査しやすいです
* GUIを確認しながら実行し、期待通りの動作をしていることの確認
* GUI/CUIからVagrantから行おうとしている操作を実行し正常に操作できることの確認
* 削除に失敗しているリソースがあれば手動で削除する
* カレントディレクトリ下の.vagrant配下にゴミが残っている場合は削除する

たまに、SSH接続がタイミングの問題で失敗していることがあります。この場合には、Ctrl-zで一度処理を止めて仮想マシンの起動が完了してから再開すると正常に動作します。