Page List

Search on the blog

2017年6月27日火曜日

[Blog Reading] Building a Real-Time Streaming ETL Pipeline in 20 Minutes

Confluentのブログを読んだ。
最近KafkaまわりのOSSにプルリク送ってみたりして、Confluent熱が個人的に高まっている。

Building a Real-Time Streaming ETL Pipeline in 20 Minutes

以下、感想・考えてみたことなど。

  • Kafkaってなんなのか一言で説明するのは難しいが、このブログにあるように「分散ストリーミング基盤」というのが良さそう。
  • Streaming ETLという概念がやばい。Batch ETLでやっているような集計処理をバックグラウンドでリアルタイムに実行できるやつ。
    • ブログの下の方で引用されているが、簡単なサンプルアプリがあるので見てみるとイメージがわく
  • 「複数のアプリが同じデータソースを参照していると密結合になる」みたいな話を聞いたことがあったが、その感覚が分かった。例えば、アプリAがデータ生成するテーブルAがあったとして、これをみたい他のアプリB, C, D, ..があったとする。アプリB, C, D, ..からテーブルAを直接参照すると以下のような問題が起こる。
    • 参照者が増えてくると、テーブルAのアクセス負荷が増える(Producer:Consumer = 1:N)
    • アプリAが自由にテーブルAのスキーマを変更できない(テーブルAの変更は参照側のアプリに影響を与える)
    • 参照で集計処理をしたい場合は、日次バッチになってしまう(負荷が高いのでリアルタイムで集計できない)

2017年6月24日土曜日

VagrantのゲストOS間でホスト名参照

 Vagrantfileでホスト名を指定してるのに何故か参照できなかった。

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu15.04"
  config.ssh.insert_key = false
  config.vm.define "kafka-base" do |server|
    server.vm.network "private_network", ip: "192.168.33.11"
    server.vm.hostname = "kafka-base"
  end
  config.vm.define "kafka-connector" do |server|
    server.vm.network "private_network", ip: "192.168.33.12"
    server.vm.hostname = "kafka-connector"
  end
end

vagrant@kafka-base:~$ hostname
kafka-base
vagrant@kafka-base:~$ ping kafka-connector
ping: unknown host kafka-connector
vagrant@kafka-base:~$ cat /etc/hosts
127.0.0.1 kafka-base  kafka-base
127.0.0.1 localhost
127.0.1.1 vagrant-ubuntu-trusty.vagrantup.com vagrant-ubuntu-trusty
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

vagrant-hostsというプラグインを入れてみると解決した。
$ vagrant plugin install vagrant-hosts

以下のようにserver.vm.provisionの行を追加すると、ホスト名が設定され、さらにゲストOSの/etc/hostsに仮想マシンのホスト名情報が追記される。
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu15.04"
  config.ssh.insert_key = false

  config.vm.define "kafka-base" do |server|
    server.vm.network "private_network", ip: "192.168.33.11"
    server.vm.provision :hosts, :sync_hosts => true
  end
  config.vm.define "kafka-connector" do |server|
    server.vm.network "private_network", ip: "192.168.33.12"
    server.vm.provision :hosts, :sync_hosts => true
  end
end

以下のように動作確認してみると、ホスト 名でゲストOS間の通信ができることが分かる。
vagrant@kafka-base:~$ hostname
kafka-base
vagrant@kafka-base:~$ ping kafka-connector
PING kafka-connector (192.168.33.12) 56(84) bytes of data.
64 bytes from kafka-connector (192.168.33.12): icmp_seq=1 ttl=64 time=0.470 ms
64 bytes from kafka-connector (192.168.33.12): icmp_seq=2 ttl=64 time=0.348 ms
^C
--- kafka-connector ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.348/0.409/0.470/0.061 ms
vagrant@kafka-base:~$ cat /etc/hosts
127.0.0.1 localhost
127.0.1.1 kafka-base
192.168.33.11 kafka-base
192.168.33.12 kafka-connector

Vagrantで共通のssh private keyを使う

 Vagrantで複数の仮想マシンを立ち上げて、仮想マシン間でsshの秘密鍵を共有したい場合がある。Vagrant 1.8でのデフォルトの設定ではマシンごとに異なる秘密鍵が生成される。

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu15.04"
  config.vm.define "kafka-base" do |server|
    server.vm.network "private_network", ip: "192.168.33.11"
  end
  config.vm.define "kafka-connector" do |server|
    server.vm.network "private_network", ip: "192.168.33.12"
  end
end

秘密鍵情報を確認。仮想マシンごとに別の秘密鍵が生成されていることが分かる。
$ vagrant ssh-config
Host kafka-base
  HostName 127.0.0.1
  User vagrant
  Port 2200
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /Users/kenjih/work/vagrant_ansible_kafka/vagrant/.vagrant/machines/kafka-base/virtualbox/private_key
  IdentitiesOnly yes
  LogLevel FATAL

Host kafka-connector
  HostName 127.0.0.1
  User vagrant
  Port 2201
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /Users/kenjih/work/vagrant_ansible_kafka/vagrant/.vagrant/machines/kafka-connector/virtualbox/private_key
  IdentitiesOnly yes
  LogLevel FATAL

 しかし、デプロイ自動化を行う場合など、共通の秘密鍵を使えると便利なことが多い。そのような場合は以下のようにconfig.ssh.insert_key = falseという設定を追加すればよい。

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu15.04"
  config.ssh.insert_key = false
  config.vm.define "kafka-base" do |server|
    server.vm.network "private_network", ip: "192.168.33.11"
  end
  config.vm.define "kafka-connector" do |server|
    server.vm.network "private_network", ip: "192.168.33.12"
  end
end

秘密鍵情報を確認してみると、共通の秘密鍵を利用できることが分かる。
kenjih$ vagrant ssh-config
Host kafka-base
  HostName 127.0.0.1
  User vagrant
  Port 2200
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /Users/kenjih/.vagrant.d/insecure_private_key
  IdentitiesOnly yes
  LogLevel FATAL

Host kafka-connector
  HostName 127.0.0.1
  User vagrant
  Port 2201
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /Users/kenjih/.vagrant.d/insecure_private_key
  IdentitiesOnly yes
  LogLevel FATAL

2017年6月11日日曜日

VagrantとAnsibleでKafka環境をつくる(8)

 Vagrant、Ansibleで作ったKafka環境で動作確認をしてみる。
以下の操作はすべてプロジェクトのrootディレクトリから実行するものとします。

まずvagrantで仮想マシンを起動する。
$ cd vagrant
$ vagrant up

続いてansibleでplaybookを適用する。
$ cd ansible
$ ansible-playbook site.yml 

まずはrest proxyと疎通確認を行う。
$ curl 192.168.33.11:8082/topics
["_schemas"]

rest proxy経由でKafkaにデータを送ってみる。
$ curl -X POST -H "Content-Type: application/vnd.kafka.json.v2+json" \
 --data '{"records":[{"value":{"name": "testUser"}}]}' \
      "192.168.33.11:8082/topics/jsontest"
{"offsets":[{"partition":0,"offset":0,"error_code":null,"error":null}],"key_schema_id":null,"value_schema_id":null}

consumerを作成し、先ほど作成したjsontestトピックをサブスクライブする。
$ curl -X POST -H "Content-Type: application/vnd.kafka.v2+json" -H "Accept: application/vnd.kafka.v2+json" \
--data '{"name": "my_consumer_instance", "format": "json", "auto.offset.reset": "earliest"}' \
http://192.168.33.11:8082/consumers/my_json_consumer
{"instance_id":"my_consumer_instance","base_uri":"http://192.168.33.11:8082/consumers/my_json_consumer/instances/my_consumer_instance"}

$ curl -X POST -H "Content-Type: application/vnd.kafka.v2+json" --data '{"topics":["jsontest"]}' \
http://192.168.33.11:8082/consumers/my_json_consumer/instances/my_consumer_instance/subscription

もう1つメッセージを送ってみる。
$ curl -X POST -H "Content-Type: application/vnd.kafka.json.v2+json" \
 --data '{"records":[{"value":{"name": "testUserXXX"}}]}' \
      "192.168.33.11:8082/topics/jsontest"
{"offsets":[{"partition":0,"offset":1,"error_code":null,"error":null}],"key_schema_id":null,"value_schema_id":null}

メッセージをコンシュームする。
$ curl -X GET -H "Accept: application/vnd.kafka.json.v2+json" \       
http://192.168.33.11:8082/consumers/my_json_consumer/instances/my_consumer_instance/records                               
[{"key":null,"value":{"name":"testUser"},"partition":0,"offset":0,"topic":"jsontest"},{"key":null,"value":{"name":"testUserXXX"},"partition":0,"offset":1,"topic":"jsontest"}]

データの送受信を確認できたので、テスト用のコンシューマーを削除する。
$ curl -X DELETE -H "Accept: application/vnd.kafka.v2+json" \
      http://192.168.33.11:8082/consumers/my_json_consumer/instances/my_consumer_instance

VagrantとAnsibleでKafka環境をつくる(7)

 前回マニュアルで試したsystemdからconfluentコンポーネントを起動するための設定をansible化した(成果物)。利用するコンポーネントは以下の4つなので、それぞれのコンポーネント別にroleを作った。

 serviceの設定スクリプトは、Jinja2を使ってtemplatesディレクトリ配下に置いている。taskではtemplatesに置かれたテンプレートを/etc/systemd/system/配下に格納する。設定が変更されると、handlerで指定したようにserviceが起動される。

 以下にzookeeper roleの場合のサンプルを載せておく。

ansible/roles/zookeeper/templates/zookeeper.service.j2
[Unit]
Description=confluent platform zookeeper
After=network.target

[Service]
ExecStart=/usr/bin/zookeeper-server-start /etc/kafka/zookeeper.properties
ExecStop=/usr/bin/zookeeper-server-stop

[Install]
WantedBy=multi-user.target

ansible/roles/zookeeper/tasks/main.yml
- name: zookeeper systemd script
  template:
    src: zookeeper.service.j2
    dest: /etc/systemd/system/zookeeper.service
    owner: root
    group: root
    mode: 644
  notify: start zookeeper

ansible/roles/zookeeper/handlers/main.yml
- name: start zookeeper
  service: name=zookeeper state=started enabled=yes

2017年6月5日月曜日

VagrantとAnsibleでKafka環境をつくる(6)

 zookeeperをサービス登録して、systemdから起動させるようにしてみた。
Ansible化はまだ出来ていないが、とりあえず手動で設定&起動できた。

以下のようなファイルを作っておく。
vagrant@vagrant-ubuntu-trusty:~$ cat /etc/systemd/system/zookeeper.service 
[Unit]
Description=confluent platform zookeeper
After=network.target

[Service]
ExecStart=/usr/bin/zookeeper-server-start /etc/kafka/zookeeper.properties
ExecStop=/usr/bin/zookeeper-server-stop

[Install]
WantedBy=multi-user.target

After=network.targetとすることで、ネットワーク起動後にサービスを開始させるという意味になる。
WantedByのところには、ランレベルを設定する。
multi-user.targetとするとマルチユーザモードで使用されるサービスとなる。

ちなみに、targetの一覧は以下のようにして参照できる。
vagrant@vagrant-ubuntu-trusty:~$ systemctl list-units --type target
UNIT                  LOAD   ACTIVE SUB    DESCRIPTION
basic.target          loaded active active Basic System
cryptsetup.target     loaded active active Encrypted Volumes
getty.target          loaded active active Login Prompts
graphical.target      loaded active active Graphical Interface
local-fs-pre.target   loaded active active Local File Systems (Pre)
local-fs.target       loaded active active Local File Systems
multi-user.target     loaded active active Multi-User System
network-online.target loaded active active Network is Online
network.target        loaded active active Network
nfs-client.target     loaded active active NFS client services
paths.target          loaded active active Paths
remote-fs-pre.target  loaded active active Remote File Systems (Pre)
remote-fs.target      loaded active active Remote File Systems
rpcbind.target        loaded active active RPC Port Mapper
slices.target         loaded active active Slices
sockets.target        loaded active active Sockets
swap.target           loaded active active Swap
sysinit.target        loaded active active System Initialization
time-sync.target      loaded active active System Time Synchronized
timers.target         loaded active active Timers

サービスとして認識しているか確認。
vagrant@vagrant-ubuntu-trusty:~$ sudo systemctl list-unit-files --type=service | grep zookeeper
zookeeper.service                      disabled

サービス有効化。
vagrant@vagrant-ubuntu-trusty:~$  sudo systemctl enable zookeeper
Created symlink from /etc/systemd/system/multi-user.target.wants/zookeeper.service to /etc/systemd/system/zookeeper.service.

サービス起動&確認。
vagrant@vagrant-ubuntu-trusty:~$ sudo systemctl start zookeeper

vagrant@vagrant-ubuntu-trusty:~$ sudo systemctl status zookeeper
● zookeeper.service - confluent platform zookeeper
   Loaded: loaded (/etc/systemd/system/zookeeper.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2017-06-05 14:22:49 GMT; 16s ago

デフォルトポートでlistenしているか念のため確認。
vagrant@vagrant-ubuntu-trusty:~$ pgrep -f zookeeper
4542
vagrant@vagrant-ubuntu-trusty:~$ sudo lsof -a -i -p 4542
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
java    4542 root   98u  IPv6  25718      0t0  TCP *:56431 (LISTEN)
java    4542 root  109u  IPv6  25729      0t0  TCP *:2181 (LISTEN)

VagrantとAnsibleでKafka環境をつくる(5)

 前回Javaが入ったので、Kafka環境を入れてみた(成果物)。
KafkaはConfluent Platformを使う。手動でインストールすると以下のようになる。

# install confluent public key
$ wget -qO - http://packages.confluent.io/deb/3.2/archive.key | sudo apt-key add -

# add confluent repository
$ sudo add-apt-repository "deb [arch=amd64] http://packages.confluent.io/deb/3.2 stable main"

# update apt
$ sudo apt-get update 

# install confluent platform
$ sudo apt-get install confluent-platform-2.11

上のインストール作業を行うplaybookは以下のようになる。

[ansible/roles/common/tasks/install_confluent.yml]
- name: install confluent public key
  apt_key: url="http://packages.confluent.io/deb/{{ confluent_repo_version }}/archive.key" state="present"

- name: add confluent repository
  apt_repository: repo="deb [arch=amd64] http://packages.confluent.io/deb/{{ confluent_repo_version }} stable main"

- name: update apt
  apt: update_cache=true

- name: install confluent platform
  apt: "name=confluent-platform-2.11={{ confluent_package_version }} state=present"

{{ XXX }}のところは変数になっている。変数の値は以下のようにvarsディレクトリ内のファイルで定義できる。

[ansible/roles/common/vars/main.yml]
confluent_repo_version: 3.2
confluent_package_version: 3.2.1-1

2017年6月4日日曜日

VagrantとAnsibleでKafka環境をつくる(4)

 Oracle Java1.8を入れるplaybookを書いた(成果物)。

 playbookはroleごとにまとめるのがbest practiceらしい。サーバの役割毎(common, web, dbなど)にroleを設定しているサンプルが多いので、それにならって、common, zookeeper, kafka, schema-registry, rest-proxyというroleをつくろうと思う。

 今回書いたのはJavaのところだけなので、common roleにtaskを書いた。

作成したplaybookのsyntaxチェック。
$ ansible-playbook roles/common/tasks/main.yml --syntax-check

playbook: roles/common/tasks/main.yml

playbookを実行する。
$ ansible-playbook roles/common/tasks/main.yml

PLAY [all] **************************************************************************

TASK [Gathering Facts] **************************************************************
ok: [192.168.33.11]

TASK [Install add-apt-repostory] ****************************************************
changed: [192.168.33.11]

TASK [Add Oracle Java Repository] ***************************************************
changed: [192.168.33.11]

TASK [Accept Java 8 License] ********************************************************
changed: [192.168.33.11]

TASK [Install Oracle Java 8] ********************************************************
changed: [192.168.33.11] => (item=[u'oracle-java8-installer', u'ca-certificates', u'oracle-java8-set-default'])

PLAY RECAP **************************************************************************
192.168.33.11              : ok=5    changed=4    unreachable=0    failed=0

仮想マシンにJava 1.8がインストールされたことを確認。
$ vagrant ssh
vagrant@vagrant-ubuntu-trusty:~$ java -version
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)

VagrantとAnsibleでKafka環境をつくる(3)

 Ansibleのplaybookを書こうとしたが、
  • まずはマニュアルで環境を作ってみてうまくいったらplaybookを書きたい
  • マニュアルでいろいろ試行錯誤して環境汚してしまうのは避けたい
ということで何か便利なツールがないか探していたところ、saharaというvagrantのプラグインを見つけた。

saharaを使うと、仮想マシンの環境をサンドボック状態にしてコミット/ロールバックを行うことができる。

以下実行例。

プラグインをインストール。
$ vagrant plugin install sahara
$ vagrant sandbox -h
Usage: vagrant sandbox  []

Available subcommands:
     commit
     off
     on
     rollback
     status

sandboxモードを有効にする。
$ vagrant sandbox on

$ vagrant sandbox status
[default] Sandbox mode is on

sandboxモードの状態で仮想マシンに何かインストールしてみる。
$ vagrant ssh default

vagrant@vagrant-ubuntu-trusty:~$ tmux
The program 'tmux' is currently not installed. You can install it by typing:
sudo apt-get install tmux

vagrant@vagrant-ubuntu-trusty:~$ sudo apt-get install tmux

vagrant@vagrant-ubuntu-trusty:~$ tmux -V
tmux 1.9

ロールバックする。
$ vagrant sandbox rollback

上記のインストールはロールバックされる。
$ vagrant ssh 

vagrant@vagrant-ubuntu-trusty:~$ tmux
The program 'tmux' is currently not installed. You can install it by typing:
sudo apt-get install tmux

VagrantとAnsibleでKafka環境をつくる(2)

Vagrantで作った仮想マシンにAnsibleから接続できるようになった(成果物)。

まず、仮想マシンにsshするときの秘密鍵の場所を調べておく。
kenjih$ vagrant ssh-config
Host default
  HostName 127.0.0.1
  User vagrant
  Port 2222
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /Users/kenjih/work/vagrant_ansible_kafka/vagrant/.vagrant/machines/default/virtualbox/private_key
  IdentitiesOnly yes
  LogLevel FATAL

ユーザと秘密鍵の場所をオプション指定するとansibleで仮想マシンに接続できる。
kenjih$ ansible -i provisioning/hosts all -m ping -u vagrant --private-key=../vagrant/.vagrant/machines/default/virtualbox/private_key
192.168.33.11 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
} 

が、毎回オプション書くのは面倒なのでconfigファイルを書くといいらしい。 以下のようなファイルをカレントディレクトリに作っておく。
$ cat ansible.cfg
[defaults]
hostfile = provisioning/hosts
remote_user = vagrant
private_key_file = /Users/kenjih/work/vagrant_ansible_kafka/vagrant/.vagrant/machines/default/virtualbox/private_key

すると、オプションなしで接続できる。
$ ansible all -m ping          
192.168.33.11 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}

接続できたので、ansibleから任意のコマンドを実行してみる。
kenjih$ ansible all -a 'whoami'
192.168.33.11 | SUCCESS | rc=0 >>
vagrant

kenjih$ ansible all -a 'uname -a'
192.168.33.11 | SUCCESS | rc=0 >>
Linux vagrant-ubuntu-trusty 3.19.0-15-generic #15-Ubuntu SMP Thu Apr 16 23:32:37 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

2017年6月3日土曜日

Distributed Code Jam Round 1 2017 E. query_of_death

問題
GetValue(i)を呼ぶとi番目の値(0 or 1)が返ってくる。
ただし、あるiを使ってGetValue(i)を呼ぶとシステムが死んでしまう(他のノードに対しては影響はない)。以下ではこのiをi_qodと呼ぶ。
i = 1 〜 NまでのGetValue(i)の和を求めよ。

制約
N <= 10^8
ノード数: 100

解法
semiexp.さんの解法が綺麗。
まずノードをmasterとslaveに分ける。
masterは計算する範囲をslaveに渡す。slaveは与えられた部分問題をといてmasterに返却する。1回目のbatchで1つのslaveが死ぬが、i_qodを含む範囲が1/99に絞られる。続いて2回目のbatchでも1つのslaveが死ぬが、i_qodを含む範囲がさらに1/98に絞られる...というふうに分割統治的に解ける。見ればわかるけど、自分じゃ思いつかない。

ソースコード
// DCJ templates begin
template <typename T>
void PutStruct(int target, const T &v) {
  char *p = (char *) &v;
  for (int i = 0; i < sizeof(T); i++) {
    PutChar(target, p[i]);
  }
}

template <class T>
T GetStruct(int source) {
  char buf[sizeof(T)];
  for (int i = 0; i < sizeof(T); i++) {
    buf[i] = GetChar(source);
  }
  return *((T *)buf);
}
// DCJ templates end

int calc(pair<int, int> pr) {
  int l, r;
  tie(l, r) = pr;

  if (l == r) return 0;
  if (r - l == 1) return GetValue(l);

  int sum = 0;
  for (int i = l; i < r; i++)
    sum += GetValue(i);

  int ck = 0;
  for (int i = 0; i < 50; i++)
    ck += GetValue(l);

  if (ck != 0 && ck != 50)
    return -1;
  return sum;
}

int main() {
  int rank = MyNodeId();
  int NN = NumberOfNodes();
  
  if (!rank) {
    long long L = 0;
    long long R = GetLength();
    set<int> alive;
    int sum = 0;
    
    for (int i = 1; i < NN; i++)
      alive.insert(i);
    
    for (;;) {
      bool update = false;

      vector<int> vs(ALL(alive));
      for (int i = 0; i < vs.size(); i++) {
        int l = L + i * (R - L) / vs.size();
        int r = L + (i + 1) * (R - L) / vs.size();
        PutStruct(vs[i], make_pair(l, r));
        Send(vs[i]);
      }

      for (int i = 0; i < vs.size(); i++) {
        Receive(vs[i]);
        int s = GetInt(vs[i]);
        if (s == -1) {
          update = true;
          int l = L + i * (R - L) / vs.size();
          int r = L + (i + 1) * (R - L) / vs.size();
          L = l, R = r;
          PutStruct(vs[i], make_pair(-1, -1));
          Send(vs[i]);
          alive.erase(vs[i]);
        } else {
          sum += s;
        }
      }
      if (!update)
        break;
    }
    
    for (auto &x : alive) {
      PutStruct(x, make_pair(-1, -1));
      Send(x);
    }
    
    cout << sum << endl;
  } else {
    for (;;) {
      Receive(0);
      auto pr = GetStruct<pair<int, int> >(0);
      if (pr.first == -1)
        break;
      int s = calc(pr);
      PutInt(0, s);
      Send(0);
    }
  }

  return 0;
}

2017年6月2日金曜日

VagrantとAnsibleでKafka環境をつくる(1)

 まずはVagrantで仮想マシンの作成、起動、停止をするところから。

boxの確認
kenjih$ vagrant box list
centos6     (virtualbox, 0)
ubuntu14.04 (virtualbox, 0)

boxの追加
kenjih$ vagrant box add ubuntu15.04 https://github.com/kraksoft/vagrant-box-ubuntu/releases/download/15.04/ubuntu-15.04-amd64.box

再びBoxの確認(ubuntu15.04が追加されている)
kenjih$ vagrant box list
centos6     (virtualbox, 0)
ubuntu14.04 (virtualbox, 0)
ubuntu15.04 (virtualbox, 0)

初期化
kenjih$ vagrant init ubuntu15.04

仮想マシン起動
kenjih$ vagrant up

仮想マシンへのログイン
kenjih$ vagrant ssh
vagrant@vagrant-ubuntu-trusty:~$
vagrant@vagrant-ubuntu-trusty:~$ uname -a
Linux vagrant-ubuntu-trusty 3.19.0-15-generic #15-Ubuntu SMP Thu Apr 16 23:32:37 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

仮想マシン状態確認(状態がrunningになっている)
kenjih$ vagrant status
default                   running (virtualbox)

仮想マシン停止
kenjih$ vagrant halt

再び仮想マシン状態確認(状態がpoweroffになっている)
kenjih$ vagrant status
default                   poweroff (virtualbox)