Dockerコンテナのようなランダムに名前を生成する`name`コマンドを作った(?)

“Dockerコンテナのような"とタイトルには書いたが、まんまDockerで使われているLibraryをコマンド化しただけのもの。果たして、作ったと言っていいのか疑わしいレベル。

イマ作っているアプリケーションでランダムな名前ユーザのディレクトリを幾つか作る必要があった。Alice, Bob, Carol, Daveと作っていっても良かったんだけど、味気がない。Dockerコンテナはランダムに名前つけてたということを思い出したため、これを利用しようと思った。

結果として、Dockerコンテナのおもしろい名前で書かれていることが全てで、フラグつけてラップしただけのコマンドである(もうすでにありそう)。

リポジトリGitHub: ringohub/nameで公開してます。

Install

go get github.com/ringohub/name

Usage

$ name -h
Usage of name:
  -n=1: Number of generate names
$ name
jolly_kirch
$ name -n 5
sleepy_pare
tender_carson
kickass_bartik
happy_meitner
agitated_pike

References

React.jsでES6の文法を使って defaultProps などを設定する

環境

Tools Version
react-tools 0.13.1
jsx 0.12.2
react.js 0.13.1
JSXTransformer.js 0.13.1

react-toolsnpmでインストールし、jsx--harmonyオプションを付けてコンパイルした。

npm install -g react-tools
jsx --harmony -w src build

方法

var Hello = React.createClass({
  getDefaultProps: function() {
    return {name: "Default Props"};
  },

  render: function() {
    return <div>Hello {this.props.name}</div>;
  }
});

class Hello extends React.Component {
  constructor(props) {
    super(props);
    console.log(props);
    console.log(this.props);
    this.state = {name: this.props.initialName};
  }

  render() {
    return <div>Hello {this.state.name}</div>;
  }
}
Hello.defaultProps = {initialName: "Default Props"};

にする。

試行錯誤

普通にdefaultPropsを記述すると、

var Hello = React.createClass({
  getDefaultProps: function() {
    return {name: "Default Props"};
  },

  render: function() {
    return <div>Hello {this.props.name}</div>;
  }
});

となる。 これを、ES6で記述すると、

class Hello extends React.Component {
  getDefaultProps() {
    return  {name: "Default Props"};
  }

  render() {
    return <div>Hello {this.props.name}</div>;
  }
}

となるとおもいきや、defaultPropsが全然効かない。

Reusable Componentsのドキュメントを読むと、propTypesdefaultPropspropTypesはどうやら書き方がちょっと違うらしい。

The API is similar to React.createClass with the exception of getInitialState. Instead of providing a separate getInitialState method, you set up your own state property in the constructor.

Another difference is that propTypes and defaultProps are defined as properties on the constructor instead of in the class body.

サンプルを見ながら書き換える。

export class Hello extends React.Component {
  constructor(props) {
    super(props);
    console.log(props);
    console.log(this.props);
    this.state = {name: this.props.initialName};
  }

  render() {
    return <div>Hello {this.props.name}</div>;
  }
}
Hello.defaultProps = {initialName: "Default Props"};

コンパイルは通るが、ブラウザで表示すると以下の様なエラーが出る。

Uncaught Error: Parse Error: Line 3: Illegal export declaration
    at file:///Users/yoshiki_aoki/work/react-tutorial/build/alone.js:3:undefined
export var ____Classm=React.Com ...
^

ちなみに、React.jsのページにあるJSX Compilerで、ドキュメントに載っているコードをコンパイルすると同じエラーが出る。

試しにexportをはずすと、エラーは発生しないがデフォルト値がセットされていない。 これは、別の箇所が原因でrenderpropsstateに変更するのを忘れていた事が原因だった。

class Hello extends React.Component {
  constructor(props) {
    super(props);
    console.log(props);
    console.log(this.props);
    this.state = {name: this.props.initialName};
  }

  render() {
    return <div>Hello {this.state.name}</div>;
  }
}
Hello.defaultProps = {initialName: "Default Props"};

これで無事表示された。

References

DockerRegistryのコンテナ一覧を見るDockerIndexをつくった

先日、会社のエンジニア全員が参加するハッカソンでDocker Indexというアプリを作りました。

名前はさておき、Docker Index とは、Docker Registoryに登録されているコンテナを一覧表示するWebApplicationです。 Docker RegistoryはDocker Hub(のようなもの)を自分のサーバにたてられようなものです。

ただ、WebUIは一切用意してくれていないので、 会社でみんながDocker Registoryに作成したコンテナをpushしてくれていても、 どんなコンテナが存在するのか確認する術がありませんでした。

これが、作成しようと思った動機。

使用言語、フレームワーク

このハッカソンのルール(?)は、普段業務であまり使っていない言語・フレームワークを選択しよう!というもの。 そこで、何にしようかと考えたところ、DockerもGoで書かれているし、Goで書くということにしました。

フレームワークは、普段業務ではPlay2/Scalaを使っているため、雰囲気が似ているというRevelを使ってみようと思い採用しました。

そして、どうせならやっぱりDockerコンテナで動かしたいよね。

ということで、ゴールは“DockerコンテナでDocker Registoryに保存されているコンテナを一覧表示するWebUIを作る”というものを設定しました。

4, 5時間で、初めての言語、初めてのフレームワークということなので、このくらいの課題でちょうどいいかなと思います。 ハッカソンは何か動くものを作るのが目標なので。

つくってみた

とりあえず、ローカルで環境をつくりgo/revelの環境をつくり、hello worldを済ませました。

最初IntelliJでやっていたんだけど、微妙な感じだったので(うまく設定できてない?)atomでやりました。 入れたパッケージは多分こんな感じ

  • typester/atom-gocode
  • joefitzgerald/go-plus

ドキュメントとかは適当にココらへんを読んだり、Golangテーブルでハッカソンしてる人に聞いたりしてしました。

内部的にはディレクトリの内容をみて、一覧しているだけなので大したことはしてません。

しかも、パッケージの切り方がよくわからず、全てコントローラーに突っ込んであります(※ハッカソンです)。

そして、できたのがこんなかんじ。

docker-index

問題

パッケージの切り方がよくわからなかった

なんか、単純にpackageを/できって、ディレクトリ構造と合わせてみてもならなかったので、時間の都合上後回しにしました。

docker build しようとするとbuildableじゃないと怒られる

docker buildしたときにbuildableじゃないと言われ、途中で止まってしまう問題が発生しました。
多分、実行用にいろいろしなきゃいけないんだろうなぁと思いながら、時間がないのでとりあえずrevel runで動く状態で放置してました。

Step 4 : RUN go get github.com/ringohub/docker-index
 ---> Running in cf9d1b96d14f
package github.com/ringohub/docker-index
    imports github.com/ringohub/docker-index
    imports github.com/ringohub/docker-index: no buildable Go source files in /gopath/src/github.com/ringohub/docker-index

リターンコードが0じゃないと途中で止まってしまうっぽかったので、 対症療法として、;echo ''を実行しリターンコードを誤魔化したりしてみました。

どなたか、正しいやり方教えてください。

感想

  • 半日で何かを作るのは時間的に難しいかった。
  • でも、使ったこと無い言語やフレームワークに挑戦するのは楽しい!
  • ハッカソンテーマが「出会い」ということをすっかり忘れていて、発表が始まってから気づいた
  • gopherがかわいくみえてきた(人形欲しい)

来年もまたがんばります。

成果物

今回作った、revelアプリやDockerfileはこちらにおいてあります。
突っ込みどころ満載なので、プルリクし放題です。
golangerたちのプルリクを頂けると勉強になるとおもうのでお待ちしております!

dwanGoも開催されます!

Macのdockerを1.0にアップグレードする

まだ、docker 1.0になってからアップグレードしてないMacがあったので、アップグレードしました。

古いboot2dockerのアンインストール

次の手順でboot2dockerをインストールしていた人はこの手順を行う必要があります。

# これでインストールしてた人は一度消す必要がある
$ brew tap homebrew/binary
$ brew install boot2docker docker

1.0からbrew caskでインストールできるようになりました。 逆に、普通にbrewではインストールできないようになりました。 そのため、一度boot2dockerをアンインストールします。

boot2dockerが起動していたらstopします。

$ boot2docker stop
[2014-06-15 13:50:35] Shutting down boot2docker-vm...

使っていたtiny core Linuxを削除します。

$ boot2docker delete

boot2dockerをアンインストールします。さらば。

$ brew uninstall boot2docker docker
Uninstalling /usr/local/Cellar/boot2docker/0.9.1...

brew caskでboot2dockerをインストール

まずは、updateしましょう。

$ brew update

caskが入っていない場合は、インストールします。

$ brew tap phinze/homebrew-cask
$ brew install brew-cask

入っている場合はupgrade

$ brew upgrade brew-cask

あとはインストールするだけ!

brew cask install boot2docker
==> Downloading https://github.com/boot2docker/osx-installer/releases/download/v1.0.0/Boot2Docker-1.0.0.pkg
######################################################################## 100.0%
==> Running installer for boot2docker; your password may be necessary.
Password:
==> installer: Package name is Boot2Docker for Mac OS X
==> installer: Upgrading at base path /
==> installer: The upgrade was successful.
 boot2docker installed to '/opt/homebrew-cask/Caskroom/boot2docker/1.0.0' (135M)

以前のboot2dockerと比べてもコマンドが増えてる。。

# old
$ boot2docker
Usage /usr/local/bin/boot2docker {init|start|up|save|pause|stop|restart|status|info|delete|ssh|download}
# new
$ boot2docker
Usage: boot2docker [<options>] {help|init|up|ssh|save|down|poweroff|reset|restart|config|status|info|ip|delete|download|version} [<args>]

動作確認

[IP Address]の部分は適当なものを入れてください。

$ boot2docker init
$ boot2docker up
$ export DOCKER_HOST=tcp://[IP Address]:2375
$ boot2docker ssh
Warning: Permanently added '[localhost]:2022' (RSA) to the list of known hosts.
                        ##        .
                  ## ## ##       ==
               ## ## ## ##      ===
           /""""""""""""""""\___/ ===
      ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~
           \______ o          __/
             \    \        __/
              \____\______/
 _                 _   ____     _            _
| |__   ___   ___ | |_|___ \ __| | ___   ___| | _____ _ __
| '_ \ / _ \ / _ \| __| __) / _` |/ _ \ / __| |/ / _ \ '__|
| |_) | (_) | (_) | |_ / __/ (_| | (_) | (__|   <  __/ |
|_.__/ \___/ \___/ \__|_____\__,_|\___/ \___|_|\_\___|_|
boot2docker: 1.0.0
             master : 16013ee - Mon Jun  9 16:33:25 UTC 2014

無事upgradeできました。Moby Dockかわいい。

$ docker version
Client version: 1.0.0
Client API version: 1.12
Go version (client): go1.2.1
Git commit (client): 63fe64c
Server version: 1.0.0
Server API version: 1.12
Go version (server): go1.2.1
Git commit (server): 63fe64c

出会ったエラー

no such file or directory

DOCKER_HOSTをExportしてないと出ます。

$ docker images
Get http:///var/run/docker.sock/v1.12/images/json: dial unix /var/run/docker.sock: no such file or directory

DOCKER_HOSTをExportしましょう。

export DOCKER_HOST=tcp://[IP Address]:2375

permission denied

悩んだ。。

VPNにつないでいるとおかしいっぽいです(◞‸◟)。 VPNを切りましょう。VPNに接続したままやる方法はよくわかりません。

$ docker images
Get http://[IP Address]:2375/v1.12/images/json: dial tcp [IP Address]:2375: permission denied

参考

Scientific LinuxのDockerイメージを作成する

Docker Indexに公式に提供されている、 Scientific Linuxのベースイメージがなかったので、 自分で作ってみました。

成果物はこちら。

対象のVMを作成する

まず、Scientific Linux 6.5のDocker用ベースイメージを作成したい場合、 Scientific Linux 6.5のVMを作成します。

作り方はなんでもいいですが、Packerを使って作成する手順をまとめたのがこちらです。

以降の作業はこのVMの中で行います。

Dockerのインストール

まず、ベースイメージを作るためにDocekrをインストールします。

yumにEPELリポジトリを追加

sudo rpm -ivh http://ftp.riken.jp/Linux/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm
sudo yum -y update

もう、EPELリポジトリ以外はアップデート済みの場合は、 sudo yum -y update epel-releaseでもいいです。

Dockerのインストール

Dockerのインストールは普通にyumで行うだけ。簡単!

sudo yum -y install docker-io

Dockerベースイメージの作成

febootstrapというツールを使って作成します。 (詳しく知らないけど、debootstrapみたいなもの??)

作成用のシェルスクリプトを書きます。 名前は適当にsl65.shとかにしました。

#!/bin/bash

MIRROR_URL="http://ftp.riken.jp/Linux/scientific/6.5/x86_64/os/"
MIRROR_URL_UPDATES="http://ftp.riken.jp/Linux/scientific/6.5/x86_64/updates/security/"

yum install -y febootstrap xz

febootstrap -i bash -i coreutils -i tar -i bzip2 -i gzip -i vim-minimal -i wget -i patch -i diffutils -i iproute -i yum scientific scientific65  $MIRROR_URL -u $MIRROR_URL_UPDATES
touch scientific65/etc/resolv.conf
touch scientific65/sbin/init

tar --numeric-owner -Jcpf scientific-65.tar.xz -C scientific65 .

あとは、これを実行するだけ。

sudo ./sl65.sh

動作確認

シェルスクリプトを実行すると次のようなファイルが出来てます。

[vagrant@localhost ~]$ ls -l
total 51960
-rw-rw-r--  1 vagrant vagrant 53195204 Jun  1 15:10 scientific-65.tar.xz
dr-xr-xr-x 21 root    root        4096 Jun  1 15:07 scientific65
-rwxr-xr-x  1 vagrant vagrant      595 Jun  1 15:06 sl65.sh

こいつを、dockerにインポートします。

まず、dockerを起動。

sudo service docker start

次に、インポート。 リポジトリlocal/scientificにして、tagを6.5にしました。

cat scientific-65.tar.xz | sudo docker import - local/scientific:6.5

imageを確認。

[vagrant@localhost ~]$ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
local/scientific    6.5                 ad81296d21b0        13 minutes ago      309.6 MB

docker runしてみます。

[vagrant@localhost ~]$ sudo docker run local/scientific:6.5 cat /etc/system-release
Scientific Linux release 6.5 (Carbon)

よさそう。

Docker Indexにpushする

コマンドメモしか保存していなかったので、 ここから先はScientific Linux 6.4で実行ログを収集しました。

まず、実行している(いた)コンテナ一覧をみます。

[vagrant@localhost ~]$ sudo docker ps -a
CONTAINER ID        IMAGE                  COMMAND                CREATED             STATUS                      PORTS               NAMES
a266aa1f5c10        local/scientific:6.4   cat /etc/system-rele   37 minutes ago      Exited (0) 37 minutes ago                       determined_feynman

このコンテナをコミットします。 - a266aa1f5c10psで確認したCONTAINER ID - ringo/scientificはDocker Indexで作成した自分のリポジトリ - :の後ろにタグ

[vagrant@localhost ~]$ sudo docker commit a266aa1f5c10 ringo/scientific:6.4
0bdd7adac72c6d381e0fe56320252ffbfd39f1a965964115c598f2153fd7a9a8

ringo/scientificができました。

[vagrant@localhost ~]$ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ringo/scientific    6.4                 0bdd7adac72c        10 seconds ago      308.9 MB
local/scientific    6.4                 c5cb7eb15e7e        38 minutes ago      308.9 MB

Push しましょう!!

[vagrant@localhost ~]$ sudo docker push ringo/scientific
The push refers to a repository [ringo/scientific] (len: 1)
Sending image list

Please login prior to push:
Username: ringo
Password:
Email: 
Login Succeeded
The push refers to a repository [ringo/scientific] (len: 1)
Sending image list
Pushing repository ringo/scientific (1 tags)
c5cb7eb15e7e: Image successfully pushed
0bdd7adac72c: Image successfully pushed
Pushing tag for rev [0bdd7adac72c] on {https://registry-1.docker.io/v1/repositories/ringo/scientific/tags/6.4}

ベースイメージを使ってみる

まず、pullします。

[vagrant@localhost ~]$ sudo docker pull ringo/scientific
Pulling repository ringo/scientific
0bdd7adac72c: Download complete
1a2eb0bba51b: Download complete
c5cb7eb15e7e: Download complete
ae0b1be0b6ae: Download complete
[vagrant@localhost ~]$ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ringo/scientific    6.4                 0bdd7adac72c        About an hour ago   308.9 MB
ringo/scientific    6.5                 1a2eb0bba51b        10 days ago         322.8 MB

つぎに、runします。

[vagrant@localhost ~]$ sudo docker run -i -t ringo/scientific:6.5 cat /etc/system-release
Scientific Linux release 6.5 (Carbon)

動いたー。

最後に

Scientific Linuxのベースイメージはringo/scientificにおいてあります。

また、ベースイメージを作成するのに利用した、スクリプトgithub.com/ringohub/docker-base-imageにおいてあります。 よかったら、参考にどうぞ。

おわり!

参考

Packer で Scientific Linux 6.5 の base box を作成してみる

VagrantでScientificLinux 6.5を使いたかったんだけど、 vagrantbox.esには明示的に6.5って書いてあるboxは無かった。 (Scientific Linux 6はあったけど) なので、ScientificLinux 6.5 のvagrant用base boxをpackerで作成してみた。

成果物のtemplateはGitHub: ringohub/packer-template feature/scientifi-6.5にあります。 成果物のtemplateは[GitHub: packer-templates/develop]にあります(shiguredo/packer-templates developにマージされました。ありがとうございます)。

事前準備

  1. Packer で Scientific Linux 6.1 の Box を作成してみるに書いてあるように、shiguredo/packer-templatesforkする
  2. git clone する
  3. 適当にcentos-6.5なんかをコピーしてscientific-6.5を作成する

template.jsonの編集

template.jsonにかかれている内容を変更します。 主に、osのイメージ名やDL元のURL,checksumのハッシュ値などを変更しました。 vmwareは使う予定ないけど、templateに入っていたのでついでに変更。

diff --git a/scientific-6.5/scripts/vagrant.sh b/scientific-6.5/scripts/vagrant.sh
index 76fb7bd..3b39389 100644
--- a/scientific-6.5/scripts/vagrant.sh
+++ b/scientific-6.5/scripts/vagrant.sh
@@ -1,3 +1,5 @@
+#!/bin/sh
+
 date > /etc/vagrant_box_build_time

 mkdir -pm 700 /home/vagrant/.ssh
diff --git a/scientific-6.5/template.json b/scientific-6.5/template.json
index 2ddbe77..e428542 100644
--- a/scientific-6.5/template.json
+++ b/scientific-6.5/template.json
@@ -28,10 +28,10 @@
       "type": "vagrant",
       "override": {
         "virtualbox": {
-          "output": "centos-6-5-x64-virtualbox.box"
+          "output": "scientific-6-5-x64-virtualbox.box"
         },
         "vmware": {
-          "output": "centos-6-5-x64-vmware.box"
+          "output": "scientific-6-5-x64-vmware.box"
         }
       }
     }
@@ -46,9 +46,9 @@
       "disk_size": 40520,
       "guest_os_type": "RedHat_64",
       "http_directory": "http",
-      "iso_checksum": "f21a71e8e31df73297bdd1ccd4a64a36831284bd",
+      "iso_checksum": "a95e182f6ed14a4fb36e448d6eb19a6a59a34778",
       "iso_checksum_type": "sha1",
-      "iso_url": "http://ftp.iij.ad.jp/pub/linux/centos/6.5/isos/x86_64/CentOS-6.5-x86_64-minimal.iso",
+      "iso_url": "http://ftp.riken.jp/Linux/scientific/6.5/x86_64/iso/SL-65-x86_64-2014-01-27-Install-DVD.iso",
       "ssh_username": "vagrant",
       "ssh_password": "vagrant",
       "ssh_port": 22,
@@ -68,11 +68,11 @@
       ],
       "boot_wait": "10s",
       "disk_size": 40520,
-      "guest_os_type": "centos-64",
+      "guest_os_type": "RedHat_64",
       "http_directory": "http",
-      "iso_checksum": "f21a71e8e31df73297bdd1ccd4a64a36831284bd",
+      "iso_checksum": "a95e182f6ed14a4fb36e448d6eb19a6a59a34778",
       "iso_checksum_type": "sha1",
-      "iso_url": "http://ftp.iij.ad.jp/pub/linux/centos/6.5/isos/x86_64/CentOS-6.5-x86_64-minimal.iso",
+      "iso_url": "http://ftp.riken.jp/Linux/scientific/6.5/x86_64/iso/SL-65-x86_64-2014-01-27-Install-DVD.iso",
       "ssh_username": "vagrant",
       "ssh_password": "vagrant",
       "ssh_port": 22,
@@ -87,3 +87,4 @@
     }
   ]
 }
+
  • ちなみに、guest_os_typeの一覧はVBoxManage list ostypesで一覧できます。
  • イメージのおいてあるサーバはrikenにしました。

packerでbase boxをbuildする

packerでbase boxを作成します。

$ packer build -only=virtualbox-iso template.json

ビルドすると、ディレクトリにoutputで指定したscientific-6-5-x64-virtualbox.boxが作成されています。

vagrantで稼働確認

vagrant add

作成されたboxをaddしましょう。

$ vagrant box add sl6.5 scientific-6-5-x64-virtualbox.box
==> box: Adding box 'sl6.5' (v0) for provider:
    box: Downloading: file:///Users/ringo/work/packer-templates/scientific-6.5/scientific-6-5-x64-virtualbox.box
==> box: Successfully added box 'sl6.5' (v0) for 'virtualbox'!

追加されたか確認。

$ vagrant box list
opscode-ubuntu-12.04 (virtualbox, 0)
sl6.5                (virtualbox, 0)
ubuntu14.04          (virtualbox, 0)

よしよし。

vagrnat init

適当なところでvagrant initして、適当にVagrantfileを編集します。

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

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "sl6.5"
  config.vm.network "private_network", ip: "192.168.33.10"
end

vagrant up

upしてみましょう。

$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'sl6.5'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: sl_default_1401725308602_87916
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
    default: Adapter 2: hostonly
==> default: Forwarding ports...
    default: 22 => 2222 (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Connection timeout. Retrying...
==> default: Machine booted and ready!
GuestAdditions 4.3.10 running --- OK.
==> default: Checking for guest additions in VM...
==> default: Configuring and enabling network interfaces...
==> default: Mounting shared folders...
    default: /vagrant => /Users/ringo/work/sl

いけた。

$ vagrant ssh
Last login: Tue Jun  3 00:56:37 2014 from 10.0.2.2
[vagrant@localhost ~]$ cat /etc/system-release
Scientific Linux release 6.5 (Carbon)

完成!

まとめ

packerを使って、OSのイメージからvagrant boxを作成してみました。 意外に、簡単にできるとおもいきや、下に書いてあるようなエラーでハマってたりしました。 boxは作れてupもできるんだけど、デフォルトでSSH鍵認証が出来ない状態でした。 とりあえず、作成できて良かったです。

ここから下は、興味がある人、同じ罠にはまってる人は御覧ください。 おわり。

エラー: vagrant upするとConnection timeoutする件

事象

「よしboxできた」と思ってvagrant upをしてみると、Connection timeoutがでた。 なんか、この時点でSSHっぽい予感がしてた。

$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'sl6.5'...
==> default: Matching MAC address for NAT networking...
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
    default: Adapter 2: hostonly
==> default: Forwarding ports...
  1 # -*- mode: ruby -*-
    default: 22 => 2222 (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Connection timeout. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
Timed out while waiting for the machine to boot. This means that
Vagrant was unable to communicate with the guest machine within
the configured ("config.vm.boot_timeout" value) time period.

If you look above, you should be able to see the error(s) that
Vagrant had when attempting to connect to the machine. These errors
are usually good hints as to what may be wrong.

If you're using a custom box, make sure that networking is properly
working and you're able to connect to the machine. It is a common
problem that networking isn't setup properly in these boxes.
Verify that authentication configurations are also setup properly,
as well.

If the box appears to be booting properly, you may want to increase
the timeout ("config.vm.boot_timeout") value.

試しに、vagrant sshでログインしてみると、パスワードを聞かれた。 予定ではSSHの鍵認証が行われ、すっとログインできるはずだった。 とりあえず、パスワードでログインして、authorized_keysの中を見てみると。。。

$ cat authorized_keys
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
</body></html>

Bad Requestが入ってた(◞‸◟)

原因

コピーして持ってきたtemplateの中にscripts/vagrant.shというシェルスクリプトがある。

date > /etc/vagrant_box_build_time

mkdir -pm 700 /home/vagrant/.ssh
curl -L https://raw.github.com/mitchellh/vagrant/master/keys/vagrant.pub -o /home/vagrant/.ssh/authorized_keys
chmod 0600 /home/vagrant/.ssh/authorized_keys
chown -R vagrant:vagrant /home/vagrant/.ssh

このファイルの中で、実行されているcurlがBad RequestのHTMLをDLしていた。 しかし、このcurlで叩いているURLは古く、ブラウザでアクセスすると、 https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pubにリダイレクトされる。 GitHubのrawリソースを示すURLが変わったとのこと。

ということで、次のように変更したら無事鍵が登録された。

diff --git a/scientific-6.5/scripts/vagrant.sh b/scientific-6.5/scripts/vagrant.sh
index 3b39389..658a8d6 100644
--- a/scientific-6.5/scripts/vagrant.sh
+++ b/scientific-6.5/scripts/vagrant.sh
@@ -3,6 +3,6 @@
 date > /etc/vagrant_box_build_time

 mkdir -pm 700 /home/vagrant/.ssh
-curl -L https://raw.github.com/mitchellh/vagrant/master/keys/vagrant.pub -o /home/vagrant/.ssh/authorized_keys
+curl -L https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub -o /home/vagrant/.ssh/authorized_keys
 chmod 0600 /home/vagrant/.ssh/authorized_keys

おまけ

Mac OSX 10.9 Mavericks でcurlを実行した時と、 Scientific Linux 6.5 でcurlを実行した時の結果を比較してみた。

OSXBSD系のコマンドが入っているので、GNU系のScientific Linuxとは挙動が違うのかもしれない。

まず、OSX

$ curl --version
curl 7.30.0 (x86_64-apple-darwin13.0) libcurl/7.30.0 SecureTransport zlib/1.2.5
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smtp smtps telnet tftp
Features: AsynchDNS GSS-Negotiate IPv6 Largefile NTLM NTLM_WB SSL libz
$ curl -I -L https://raw.github.com/mitchellh/vagrant/master/keys/vagrant.pub
HTTP/1.1 301 Moved Permanently
Date: Mon, 02 Jun 2014 16:46:59 GMT
Server: Apache
Location: https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub
Accept-Ranges: bytes
Via: 1.1 varnish
Age: 0
X-Served-By: cache-ty66-TYO
X-Cache: MISS
X-Cache-Hits: 0
Vary: Accept-Encoding

HTTP/1.1 200 OK
Date: Mon, 02 Jun 2014 16:46:59 GMT
Server: Apache
Content-Security-Policy: default-src 'none'
Access-Control-Allow-Origin: https://render.githubusercontent.com
X-XSS-Protection: 1; mode=block
X-Frame-Options: deny
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000
ETag: "18a9c00fd56d378c4cea4ee6e89018df8b41f9fa"
Content-Type: text/plain; charset=utf-8
Cache-Control: max-age=300
Content-Length: 409
Accept-Ranges: bytes
Via: 1.1 varnish
X-Served-By: cache-ty68-TYO
X-Cache: MISS
X-Cache-Hits: 0
Vary: Authorization,Accept-Encoding
Expires: Mon, 02 Jun 2014 16:51:59 GMT
Source-Age: 0

つぎに、Scientific Linux

[vagrant@localhost ~]$ curl --version
curl 7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
Protocols: tftp ftp telnet dict ldap ldaps http file https ftps scp sftp
Features: GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz
[vagrant@localhost ~]$ curl -I -L https://raw.github.com/mitchellh/vagrant/master/keys/vagrant.pub
HTTP/1.1 301 Moved Permanently
Date: Mon, 02 Jun 2014 16:45:49 GMT
Server: Apache
Location: https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub
Accept-Ranges: bytes
Via: 1.1 varnish
Age: 0
X-Served-By: cache-ty68-TYO
X-Cache: MISS
X-Cache-Hits: 0
Vary: Accept-Encoding

HTTP/1.1 400 Bad Request
Date: Mon, 02 Jun 2014 16:45:54 GMT
Server: Apache
Connection: close
Content-Type: text/html; charset=iso-8859-1

どちらも-Lでリダイレクト先に飛んでいるが、なぜかSLの方はBadRequest。 ふーむ。

参考

knife solo cook コマンドの誤爆を防ぐ

knife solo cookコマンドはchefリポジトリ内で実行しないと、失敗するだけでなく、

余計なnodeファイルなどが作成されてしまう。 ただ、エラーで終了してくれればいいんだけど。。。

しばらく、失敗している原因(実行するディレクトリが違う事)に気づかいない場合も多々ある。 Recipeやnodeファイルを無駄に見なおしたり。。。

ということで、 対症療法ですがaliasでなんとかしてみました。

方法

以下の関数とaliasを.zshrc.bashrcに設定するだけです。

function knife_solo_check() {
  if [ "$1" = 'solo' ] && [ "$2" = 'cook' ] && [ ! -d .chef ]; then
    \echo -e '\033[0;31mERROR:\033[0;39m Not chef repository directory.'
  else
    \knife $@
  fi
}
alias knife=knife_solo_check

内容は単純で、knifeコマンドの引数がsolo cookであるとき且つ、 実行した場所に.chefディレクトリが存在しない場合にだけエラーを表示します。

もしかしたら、こういうことにならない方法がすでにあるかもしれないし、 もっといい方法があるかもしれない。。 あったら教えて下さい。

Vagrantで起動しているVMを一覧する

VagrantVMをポコポコ起動していると、どこで何を起動して、どのVMが生きているのか良くわからなくなる。 いつも、VirtualBoxを起動して確認するのも面倒くさいしイケてないきがする。 vagrant statusはVagrantfileがある場所でしか表示されないし、 表示されてもその場にあるVMに関しての情報しか表示されない。

調べてみると、vagrantにはvagrant-global-statusというpluginがあるらしい。 なんと、このpluginをインストールすると、vagrant global-statusコマンドで、 いつでもどこでも全てのVagrantVMの状態を一覧で表示することができる。素晴らしい。

vagrant-global-status のインストール

$ vagrant plugin install vagrant-global-status 

使い方

次のコマンドを実行するとVM一覧が表示される。

$ vagrant global-status

こんな感じで表示されて便利。

/Users/ringo/work/vag
  default      running      (virtualbox)   2014-03-12 14:43:07 +0900

/Users/ringo/work/docker
  default      running      (virtualbox)   2014-03-12 14:43:59 +0900

試しにVMを一つ落として実行してみると。。。 シャットダウンした奴は表示されません。

/Users/ringo/work/docker
  default      running      (virtualbox)   2014-03-12 14:43:59 +0900

-a, --allオプションを使うと起動していないやつも表示されます。

$ vagrant global-status -a

/Users/ringo/work/vag
  default      poweroff     (virtualbox)   2014-03-12 14:43:07 +0900

/Users/ringo/work/docker
  default      running      (virtualbox)   2014-03-12 14:43:59 +0900

注意

このプラグインを入れた後に起動したVMしかリストされないので、 起動している場合は、一度落として立ち上げ直すと一覧されるようになります。

オプションはこのallとhelpしかないっぽい。

$ vagrant global-status -h
Usage: vagrant global-status [--all]
    -a, --all                        Displays information about all machines (instead of just the active ones)
    -h, --help                       Print this help

参考

VagrantでSnapShotを撮る

Vagrantプラグインvagrant-vbox-snapshotというものがある。 これを使うと簡単にスナップショットが撮れて便利なのでメモ。

スナップショットを使うと、その瞬間のVMの状態をまるごと記憶しておくことができる。

例えば、サーバに様々なミドルウェアをインストールして、ごちゃごちゃになってしまったとしても、 スナップショットを撮っておけば、インストール前の状態に戻すことができる。 ちょっと、手元でChefのレシピを流したいときなどに便利です。

vagrant-vbox-snapshot のインストール

vagrant plugin install vagrant-vbox-snapshot

使い方

  • スナップショット一覧

    vagrant snapshot list
    
  • スナップショットを撮る

    vagrant snapshot take [NAME]
    
  • スナップショットへ戻る(ロールバック

    vagrant snapshot go [NAME]
    

参考

おまけ

溜まってるドラフト記事を放出していきたい。。。

nodebrewでnode.jsのインストール

環境

前準備(Scientific Linux

ビルドに必要なパッケージをインストールします。 飛ばして、エラーが出てきたら実行するでもいいかも。Macの場合は不要。

sudo yum install gcc-c++

nodebrewを使ってnode.jsをインストール

  1. nodebrewのインストール
    • curl -L git.io/nodebrew | perl - setup
    • OS X の場合は brew install nodebrew
  2. .zshenv/.zshrc/.bashrcにPATH設定を追加
    • export PATH=$HOME/.nodebrew/current/bin:$PATH
  3. rc(もしくはenv)ファイルの再読み込み
    • . ~/.zshrc
  4. nodeのインストール
    • nodebrew install-binary v0.10.26
    • nodebrew help でhelpが見れます。
    • nodebrew ls-remote でインストール出来るバージョンの一覧を確認できます。
    • nodebrew install VERSION を使うとソースからビルドします。
    • nodebrew install latestで最新版をインストールすることができるのですが、node.jsはマイナーバージョンが偶数だと安定版なので、偶数を入れるのがオススメです。
  5. 使用するnodeのを指定
    • nodebrew use v0.11.12
    • ※ 指定できるバージョンはnodebrew listで確認できます。
  6. 確認
    • node -v

参考

``git branch -a''で消したはずのリモートブランチが出てくる

毎回、調べ直してるのでメモ。

gitで不要なリモートブランチを狩った後に、ローカルでgit branch -aを実行すると、 消したはずのブランチが残っていることがある。

これを消すには以下のコマンドを実行する。

 git fetch --prune

また、remoteの状態を見たいときは、

git remote show origin

を実行する。

参考

Devsumi 2014: 「サーバプロビジョニングのこれまでとこれから」の感想とメモ

サーバプロビジョニングのこれまでとこれから

感想

Developers Summit 2014 に参加してきました!
まずは、一番最初に出た「13-B-1」の感想から。

今はの業務はインフラ専門では無いけれども、興味があったのでセッションに参加してみました。

個人的に(仕事でも少し)Chefのrecipeとか書いたり、serverspecを使ってみたりして「面白い」と思っていたので、他にどんな技術があるのかワクワクしながら聞いてました。

インフラのコード(chefのrecipeなど)を、徹底的にGitHubで管理したり、 テスト駆動インフラをすると安定して環境が整えられていいと思います。
開発環境はChefで作ってますが、ちょっとrecipeを直したりすることが億劫でした。
今は、recipe書き換えて、動作確認して、レビューして、マージしてみたいなことを全部手動でやっていて、正直面倒臭いなぁと思うことが多々あります。
結果、自分のローカル環境だけ変更をとどめたり(あとで纏めて出せばいいやとか)してしまって、非常に良くない。
テスト駆動インフラにすることで、こまめに書き換える習慣がつきそうです。

あと最近、よく耳に入ってくるDockerとかについても少し知ることができたのでよかったです。

うちのチームの開発環境でも、ChefのレシピをCIしたり、Dockerとか使ってやってみたいなぁと思います。

いやー、このセッション楽しかった。

以下は、セッション中に書いたメモです。
間違いとか、何かあったら教えていただけると助かります。


サーバプロビジョニング

サーバプロビジョニングを3つのレイヤで整理すると、

  • Bootstrapping: OS install など
  • Configuration: サーバの設定など
    • 最近はサーバプロビジョニングはここらへんのことを指すことが多い
    • middle ware の install
    • 手動, シェルスクリプト, chef, puppet など
  • Orchestration: Fabric, capistrano など
    • わかりにくい概念
    • インフラの新しい概念とともに意味も変わってきている

のようにまとめられる。

Infrastructure as Code

歴史

  • 2005年に Puppet が登場
    • 2005年に論文が出ている
    • 源流はCFEngine(1993)
      • 宣言的: 何をしたいか(どうするかを記述しない)
      • 抽象化: 詳細の面倒を見てくれる
      • 冪等性: 必要なときだけ実行する
      • 収束化: 放っておけばどうにかなる
  • 「Infrastructure as Code」という言葉は2008年くらいに言われ始めた

Infrastructure as Code とは

  • 以下の項目からビジネスをゼロから再構築できるようにすること
    • ソースコード
    • アプリケーションのデータのバックアップ
    • サーバリソース

「コードでインフラの情報を記述する」ということを推し進めていったのがChef。 「ソフトウェアと同じ概念が使えないか?」という発想を元に、 「Infrastructure as Code」から「Test-Driven Infrastructure(テスト駆動インフラ)」へ。

テスト駆動インフラ

この、発想は Chef 周辺で盛り上がってきて、「Test Kitchen CI」というツールが登場している。 でも、「Chefしか対応してない!」ということで、作ったのが serverspec。 テスト駆動インフラの「駆動」は、インフラを記述したコードを書くことを駆動するという意味。 serverspecはインフラの状態をテストするためのツールではない(使ってもいいけど)、 インフラの状態を記述した「コード」をテストするツール。

インフラCI

ツール的には、もう使い慣れているもので、

  • Jenkins
  • Wercker
  • Travis
  • Drone

などでまわす。

GtiHub Flowによるインフラワークフロー

GitHubに連携させて、

  1. Test OK
  2. Review OK
  3. Merge OK

となる。 ここまでがひとつの流れ

Immutable Infrastructure (Disposable Components)

Immutable ~(不変)より、Disposable ~ (使い捨て)のほうが重要。

  • 動いているサーバには変更を加えない
  • 新しいサーバを構築してロードバランサーで切り替える
    • 成功したら元のサーバは破棄(ここが disposable)
    • ダメだったら切り戻す
    • 昔は(当時?)Blue-Green Deploymentと呼ばれていた(Immutable Infrastructure という言葉が出てきたのは2013くらい)
    • EC2のようなIaaSが出てきたから容易になった

Immutable/Disposable の制約で得られるメリット

Immutableにできないところはどうするのか?

  • 永続化や可変なデータをどうするか?

そこは、やはりケースバイケースになる。

Container Base Deployment

  • コンテナとは、単機能で、軽量なVM っていうイメージ。厳密には違うけど。
  • コンテナをまるごと差し替えてデプロイする
    1. . サーバにコンテナが乗っていて、その上で Middle ware が動いている
    2. . コンテナを載せる
    3. . コンテナの接続先(?)をかえる
  • Docker のポータビリティによって普及
    • ローカル環境のコンテナを本番環境でつかえる
    • ローカルで十分テストすることが出来る
    • テスト駆動して、CIでまわして、コンテナデプロイ
  • 単機能なVMのイメージで、1コンテナ1機能と単純化し、これらを組み合わせてサービスを構築する
    • サーバ部品のコンポーネント
    • 差しかえもし易い
    • テスタビリティも向上
    • IaaS上じゃなくても Bule-Green Deployment ができる
  • Mesos/YARN などと組み合わせて自動的なリソース配置

Orchestration

イメージ的には、

  • Configuration: 単一サーバで完結
  • Orchestration: 複数のサーバが関連するもの
    • LBへのノード追加
    • MuninやNagiosへのノード追加
    • アプリケーションデプロイ

とするとつかみやすい。

旧来と新しい Orchestration

  • 旧来
    • Immutable Infrastructure 前提ではない
    • サーバの増減が頻繁でないので Config. の領域でも可能
    • Command & Control 型
  • 新しい
    • Immutable Infra. Disposable component が前提
    • サーバの増減が頻繁で、Config. 領域での対応がキツイ
    • LBへの自動追加
    • Serf というツールの登場
      • ノードのクラスタリング
      • ゴシップロトコルべース
      • イベントプロパゲーション
      • Serfで、できることを Orchestration と捉えると、 Configuration との区別が明確になるのでいいのではないか

参考

Tools

MongoDB のタイムゾーンについて

MongoDB ではタイムゾーンを指定できない.

すべて,協定世界時UTC)で表現される. JSTの時刻を扱いたい場合は,mongoから取り出した時に+09:00したりしないといけない.

db.things.insert( { "time1": new Date() } )
db.things.find()

すると,

{
  "_id" : ObjectId("52f0cdeb344f397bf593bb87"),
  "time1" : ISODate("2014-02-04T11:24:27.602Z")
}

が出力される.

この「2014-02-04T11:24:27.602Z」は,ISO 8601規定されている,日付と時刻の表記である. 「T」は,日付と時刻を分ける記号である. 「Z」は,タイムゾーン協定世界時UTC)であることを示す.

どんな形で入れてもZつくから,UTCのみなんだね.

参考

OSXでJavaのバージョンを切り替える

先日,Java8で遊んでみようと思って,OSXにインストールしました.

java -versionを打つと

java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b121)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b63, mixed mode)

がでて,ちゃんと1.8になってるなよしよし.
と思って生活してたんだけども,思わぬところで事故ったので,1.6に戻す事にしました. でも,いじっているうちに良くわからなくなったので,ログとしてやったことをまとめておこうと思います.

Javaのバージョンを切り替える2つの方法

OSXJavaのバージョンを切り替える方法は2つ(しか知らない)あります.

  1. JAVA_HOMEを切り替える
  2. 非推奨: /System/Library/Frameworks/JavaVM.framework/Versionsの下のCurrentJDKを切り替える

javaコマンドの実体

まず,1.8をインストールした後,which javaを打つと,/usr/bin/javaが返ってきます. 実は,シンボリックリンクなのでls -l /usr/bin/javaでリンク先を見てみると,

java -> /System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/java

という結果が返ってきます. javaコマンドだけではなく,javacなどのコマンドも/System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands下にあるものを指してます.

MacOSXにおけるjavaのバージョンについて

Mac OSXのJavaのバージョンは一応/System/Library/Frameworks/JavaVM.framework/Versionsで管理(?)されています(本当か?).

ここの,ディレクトリをみてみると,

$ ls -l /System/Library/Frameworks/JavaVM.framework/Versions
total 40K
lrwxr-xr-x 1 root wheel  10  8 27 12:53 1.4 -> CurrentJDK/
lrwxr-xr-x 1 root wheel  10  8 27 12:53 1.4.2 -> CurrentJDK/
lrwxr-xr-x 1 root wheel  10  8 27 12:53 1.5 -> CurrentJDK/
lrwxr-xr-x 1 root wheel  10  8 27 12:53 1.5.0 -> CurrentJDK/
lrwxr-xr-x 1 root wheel  10  8 27 12:53 1.6 -> CurrentJDK/
lrwxr-xr-x 1 root wheel  10  8 27 12:53 1.6.0 -> CurrentJDK/
drwxr-xr-x 9 root wheel 306  1 27 18:57 A/
lrwxr-xr-x 1 root wheel   1  1 28 12:39 Current -> A/
lrwxr-xr-x 1 root wheel  59  8 27 12:53 CurrentJDK -> /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/

となっています.

ん?1.4も1.5も1.6もCurrentJDKを指してます. CurrentJDKは,/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/を指しています. つまり,バージョン1.4も1.5も,実は1.6だったということ.

Javaバージョンの実体

OSXJavaを提供する提供元は2箇所あります.AppleOracleです.

Appleが提供しているJavaは,CurrentJDKの指している/System/Library/Java/JavaVirtualMachinesに格納されています.

また,Oracleが提供しているパッケージを使って1.7や1.8をインストールした場合は, /Library/Java/JavaVirtualMachinesになります.

JDKの置き場所は2箇所ある.

JDKのバージョン切り替え

1. JAVA_HOMEを切り替える

OSXJavaは次のような項目で環境が決定されるそうです.

  1. Java Preferencesの優先順位をみて決定する
  2. 環境変数JAVA_HOMEが設定してある場合はこちらを優先する

Java Preferencesは,2012年10月16日にのJavaのセキュリティアップデート(Java for OS X 2012-006)で削除されました. これ以降(?),OSXJavaに提供するのはAppleからOracleに変わったようです. どちらにせよ,JAVA_HOMEを設定して上書きしてしまえばバージョンは変更できそうです.

このバージョンのパスを返す便利なコマンドが実は存在します.

java_home コマンド

このコマンドは,指定したJavaバージョンのhomeがどこにあるかを返すコマンドです. 配置されている場所は,/System/Library/Frameworks/JavaVM.framework/Versions/A/Commandsです. 実行するとこんな感じになります.

$ ./java_home -v "1.4"
Unable to find any JVMs matching version "1.4".
/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home
$ ./java_home -v "1.5"
Unable to find any JVMs matching version "1.5".
/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home
$ ./java_home -v "1.6"
/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
$ ./java_home -v "1.7"
Unable to find any JVMs matching version "1.7".
/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home
$ ./java_home -v "1.8"
/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home

1.6と1.8しかインストールしてないので,1.4,1.5と1.7は最新である1.8を指します. 1.6だけはインストールされているので,ちゃんと1.6のパスが返ってきます.

設定ファイルに記述する

.profile, .bashrc, .zshrcなどなんでもいいですが,どれかで,環境変数JAVA_HOMEに設定します. さきほどのjava_homeコマンドを使います.

export JAVA_HOME=`/System/Library/Frameworks/JavaVM.framework/Versions/A/Commands/java_home -v "1.6"`
PATH=${JAVA_HOME}/bin:${PATH}

以降,1.6の部分を,1.8に変えると簡単にバージョンを切り替えることができます.


2. 非推奨?: /System/Library/Frameworks/JavaVM.framework/Versionsの下のCurrentJDKを切り替える

この方法は,OSX標準の構造を色々といじるので,いつ,どこで,どんな事件が起こるかわかりません. そのため,個人的には非推奨です. アンチパターン?として,一応紹介しておきます.

まず,/System/Library/Frameworks/JavaVM.framework/Versionsにある,1.6以前のバージョンを整理します.

1.4 -> CurrentJDK/
1.4.2 -> CurrentJDK/
1.5 -> CurrentJDK/
1.5.0 -> CurrentJDK/
1.6 -> CurrentJDK/
1.6.0 -> CurrentJDK/
CurrentJDK -> /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/

CurrentJDKをバシバシ切り替えたいので,1.4と1.5の向き先を1.6にします. (上書きしようと思ったけれども,-f,Fつけても上書きされなかった..)

sudo rm 1.4;   sudo ln -sf 1.4.2 1.4
sudo rm 1.4.2; sudo ln -sf 1.5 1.4.2
sudo rm 1.5;   sudo ln -s 1.5.0 1.5
sudo rm 1.5.0; sudo ln -s 1.6 1.5.0
sudo rm 1.6;   sudo ln -s 1.6.0 1.6
sudo rm 1.6.0; sudo ln -s /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents 1.6.0
sudo rm CurrentJDK; sudo ln -s 1.6 CurrentJDK

次に,1.8を入れたので1.8用のリンクを追加します.

ln -s /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents 1.8.0
ln -s 1.8.0 1.8

すると,こういう構成になります.

$ ls -l
total 40K
lrwxr-xr-x 1 root wheel   5  1 28 16:39 1.4 -> 1.4.2/
lrwxr-xr-x 1 root wheel   3  1 28 16:40 1.4.2 -> 1.5/
lrwxr-xr-x 1 root wheel   5  1 28 16:45 1.5 -> 1.5.0/
lrwxr-xr-x 1 root wheel   3  1 28 16:45 1.5.0 -> 1.6/
lrwxr-xr-x 1 root wheel   5  1 28 16:46 1.6 -> 1.6.0/
lrwxr-xr-x 1 root wheel  59  1 28 16:47 1.6.0 -> /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/
lrwxr-xr-x 1 root wheel   5  1 28 15:27 1.8 -> 1.8.0/
lrwxr-xr-x 1 root wheel  55  1 28 15:26 1.8.0 -> /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/
drwxr-xr-x 9 root wheel 306  1 27 18:57 A/
lrwxr-xr-x 1 root wheel   1  1 28 12:39 Current -> A/
lrwxr-xr-x 1 root wheel   3  1 28 16:50 CurrentJDK -> 1.6/

CurrentJDKの向き先を1.8や1.6にすると切り替えられるようになりました.

javaコマンド

この状態でjava -versionコマンドを実行すると,まだ1.8のjavaが実行されてます. Current -> A下のCommand下にあるjavaコマンドを実行しています(Aってなんだ...).

Aの中身は,

$ ls -l A
total 40K
lrwxr-xr-x  1 root wheel    3  1 27 18:57 1.6 -> 1.6
drwxr-xr-x 44 root wheel 1.5K  8 27 12:53 Commands/
drwxr-xr-x  4 root wheel  136 11 18  2011 Frameworks/
drwxr-xr-x 14 root wheel  476  3 29  2013 Headers/
-rwxr-xr-x  1 root wheel 102K  8 27 12:53 JavaVM*
drwxr-xr-x 42 root wheel 1.4K  8 27 12:53 Resources/
drwxr-xr-x  3 root wheel  102  8 27 12:53 _CodeSignature/

のようになっています. 1.6のシンボリックリンクは無限ループになってます.

おそらく,1.8をインストールすると, /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/binにあるコマンドが, /System/Library/Frameworks/JavaVM.framework/Versions/A/Commandsにコピーされているような気がします. なので,これもシンボリックリンクで参照してあげます.

sudo mv Commands Commands.back
sudo ln -s /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home/bin Commands

おまけ

はてなブログのMarkdownって脚注([^1])とかうまくやってくれないんですね.

参考文献

Node Knockout 2013 にでたよ!

一人アドベントカレンダーも達成できず,年明けるまでにこの記事も投稿しておこうと思うも投稿できず,酔っ払ってテレビ見てました.あけましておめでとうございます.

先日(11/9-11),Node Knockout 2013に出ました! 書こう,書こうと思ってずっとほったらかしにしてしまいました..

Node Knockoutはnode.jsを使って行われるハッカソンで, 日をまたいで3日間,48時間開催されます. 今年で,4回めだか5回めだかだそうです.

チームmesolabsで,参戦し100位以内(75位くらい)に入ることが出来ました.

作ったもの: Walk Sharing

今回何を作ったかというと,Walk Sharingというサービス(?)です.nodeは初心者で良くわかってなかったんですが,nodeパイセンがガリガリ書いてくれたので,完成しました.

Google ストリートビューの視点を共有するもので,Navigatorの操作してるWalkingに参加すると同じ風景をリアルタイムで共有できます.Youtubeにアップロードした動画はこちら.

また,誰かが観た視点や位置を記録しておき,後から再生することができるタイムシフトもつけました.

公開した1,2日後くらいに非推奨パラメータを利用していたため,Googleの仕様変更(?)にハマってしまい審査期間に体験できないという残念なコトになってしまいました. 非推奨のものは使わないようにしましょう

やったこと

簡単に説明すると,TwitterでのOAuth認証はPassportというLibraryを使って,簡単に出来ました. ツイートも,TwitterAPI叩くだけなので難しくなかった.

一番面倒くさかったのが,スクリーンショットを撮る機能で,完成しませんでした.ストリートビューが真っ白になってしまったり,コメントだけ撮影出来てしまったり...上手く保存する方法が見つかりませんでした.本当は画像付きでツイート出来たら良かったです.

あとは,コメント描画.とりあえず,Canvasでニコニコっぽくコメントを流すようにしました.ただ,すごいファンが回り出したりしてもっと最適化する必要があると思います.コメント描画のロジックはなかなか複雑で,大変だなぁと思いました.ただ,JavaScriptでも出来なくはないんじゃあないか..と思ったので,機会があったらなにか作りたいですね.