$yuzu->log();

技術ネタなど。

エンジニア × 海外就職 × 英語で参考になりそうな記事まとめ

最近エンジニアの海外就職報告記を見かけるようになってきました。 エンジニアとしての技術力や英語力はどのぐらい必要だったのか、ビザはどうしたのか。 参考になりそうなものをまとめてみました。


kenzan100.hatenadiary.jp

ベルリンでウェブエンジニアとして働く事になった方の記事。 ワーホリビザから就労ビザに移行するやり方があるのですね。


nzmoyasystem.hatenablog.com

ニュージーランドプログラマとして働いている方のブログ。 英語力について、職場の文化について記載があります。


blog.kyanny.me

グローバル企業であるQuipperで働く上でどのぐらい英語力が求められるか詳細に書かれている記事。


hotchemi.hateblo.jp

ソフトウェアエンジニアとして英語を学ぶ上で良かったことまとめ。 「海外の会社の転職面接を受けるのは英語の勉強に良い」は、成る程と思いました。


shiumachi.hatenablog.com

英語が話せるようになれば、グローバルの人材市場で自分の価値を判断されるようになるので英語頑張ろうというお話。


d.hatena.ne.jp

Github経由でイスラエルから仕事をいただいたという話。 こういう働き方はどんどん増えていくだろうなぁ。


tango-ruby.hatenablog.com

シンガポールのスタートアップで、絶望的に英語力が無いけど技術力がある人が入社した話。 なんとか働けているようです。


chezou.hatenablog.com

「USに行きたいのなら日本法人に入るのが定石」


anond.hatelabo.jp

10年間海外で技術者として仕事をしている人からの、海外の会社で適応するためのアドバイス。


lifeiscolourful.hatenablog.com

海外移住先としてのニュージーランドのすすめ。
ニュージーランドってITのイメージなかったんですが、高給取りなのですね。


rebuild.fm

@miyagawaさんがMCをしているテック系ポッドキャスト。 IT技術やガジェットなどの話が中心ですが、@miyagawaさんがアメリカで働いていることもあり、英語やビザの細かい話などを聞ける回もある。 私は通勤時に1.5倍速で聞いてます。


タイトルが世界の最前線とかいてあるけど、中身はシリコンバレーの話です。 日本とアメリカとの仕事環境の違いや転職やレイオフの受け止め方。どのぐらい英語ができれば良いのか。ビザの話。面接突破方法など、シリコンバレーでエンジニアとして働くことを目指すなら絶対読んでおいた方がいい1冊でした。

他にも参考になりそうな記事やメディアがありましたらおしえてください。

FXシステムトレードフレームワーク Jiji をCentOS7にセットアップ

FXシステムトレードフレームワークJiji」のセットアップメモです。

「Jiji」のドキュメントにはHeroku、AWS、Dockerの3つの方法が載っており、前者2つは詳細に説明が書かれていますが、3つ目の「Dockerにインストール」はパッケージインストールが省略されています。

この記事はCentOS7での1からのセットアップ記事です。誰かの参考になれば。

Docker、Git、docker-composeのインストール

# システムをアップデート
$ sudo yum update -y

# Gitのインストール
$ sudo yum install -y git

# Dockerの最新版をインストール
$ curl -sSL https://get.docker.com/ | sh
$ docker -v
Docker version 1.10.2, build c3959b1
$ sudo systemctl start docker
$ sudo systemctl enable docker
$ sudo usermod -a -G docker YOURUSERNAME

# docker-composeをインストール
$ curl -L https://github.com/docker/compose/releases/download/1.6.0/docker-compose-`uname -s`-`uname -m` > /tmp/docker-compose
$ sudo mv /tmp/docker-compose /usr/local/bin/
$ sudo chmod +x /usr/local/bin/docker-compose

docker-compose設定ファイルのひな形をチェックアウト

$ git clone https://github.com/unageanu/docker-jiji2

オレオレ証明書の作成

# スーパーユーザにスイッチ
$ sudo su
# jiji用のディレクトリ作成、移動
$ mkdir -p /etc/ssl/certs/jiji
$ cd /etc/ssl/certs/jiji
# 秘密鍵を生成
$ openssl genrsa 2048 > server.key
# CSRを作成
$ openssl req -new -key server.key > server.csr
# サーバー証明書を作成
$ openssl x509 -sha256 -days 365 -req -signkey server.key < server.csr > server.crt
# アクセス権を制限
$ sudo chown root.root server.key
$ sudo chmod 600 server.key
# スーパーユーザから抜ける
$ exit

docker-compose.yml の編集

vim ~/docker-jiji2
jiji:
  container_name: jiji_jiji
  image: unageanu/jiji:latest
  environment:
    # サーバー内部で秘匿データの暗号化に使うキー
    # 必ず変更して使用してください。
    USER_SECRET: 20e43fa41e75c9fe958f5f11bc9e79d2174b50b
  links:
    - mongodb

mongodb:
  container_name: jiji_mongodb
  image: mongo:3.0.7
  ports:
    # MongoDBのポート番号
    # 必要に応じて変更してください。
    - "27018:27017"
  volumes:
    # MongoDBのデータを保存するディレクトリ
    # デフォルトでは、コンテナ内に作成します。(この場合、コンテナを再作成すると、データが初期化されます)
    # コメントアウトしてパスを設定することで、ホストマシンの任意のディレクトリに変更することができます。
    # './' で始めることで、docker-compose.ymlからの相対パスで指定可能です。
    # - ./path/to/data/dir:/data/db

nginx:
  container_name: jiji_nginx
  image: unageanu/jiji-nginx:latest
  links:
    - jiji
  ports:
    # Jijiのポート番号
    # 443に変更します
    - "443:443"
  volumes:
    # SSL証明書のパス
    # './path/to/server.crt' にサーバー証明書、
    # './path/to/server.key' に秘密鍵を指定します。
    # './' で始めることで、docker-compose.ymlからの相対パスで指定可能です。
    - /etc/ssl/certs/jiji/server.crt:/etc/nginx/cert/ssl.crt:ro
    - /etc/ssl/certs/jiji/server.key:/etc/nginx/cert/ssl.key:ro

Dockerコンテナ起動

$ sudo /usr/local/bin/docker-compose up -d
Creating jiji_mongodb
Creating jiji_jiji
Creating jiji_nginx

アクセス

https://<インストール先ホスト>:<docker-compose.ymlで設定したJijiのポート/デフォルトは8443>

iPhone7等の新製品を誰よりも早く予約する為に、予約サイトがオープンしたらSlackに通知する方法

Shell Script Advent Calendar 2015 8日目を担当させていただきます、@yudsuzukです。

今回は実用的なシェルスクリプトについて書きます。

GoogleのNexusやAppleiPhone等の新製品の発表は、日本時間で深夜なため、起きているのが辛いし、いつ購入サイトがオープンしたか分かり難いですよね。
気がついたら、新製品の予約サイトがオープンしてて、お目当ての製品が既に予約でいっぱい。お届け予定日数は1ヶ月後なんて事もしばしば。

そんなあなたのために、新製品の予約サイトがオープンしたらSlackに通知させるシェルスクリプトをつくりました。

今回は、実際にそのシェルスクリプトのお陰で予約ができたNexus5X、Nexus6Pの事例と、近い将来発売されるであろうiPhone7の予約サイトオープン通知スクリプトを紹介します。

Nexus5XとNexus6Pの予約サイトオープン事例

今回はGoogleの新製品、Nexus5XとNexus6Pの予約サイトがオープンした時の事例を紹介します。
予めSlackのIncoming WebHooksでWebhook URLを取得してください。

doneFile=done.txt
if [ ! -e $doneFile ]; then
    exit 0
fi

# 通知するSlackのチェンネル
channel="#test"
# 通知する時のユーザ名
username="incoming-webhook"
# 通知するユーザのアイコン
iconemoji=":shell:"
# WebHookURL
webhookUrl="https://hooks.slack.com/services/XXXXXXXX"
# 通知文言
text="nexus_5xとnexus_6pのサイトがオープンしたよ!"
# サイトURL prefix
prefixUrl="https://store.google.com/product/"
# 製品名
products=("nexus_5x" "nexus_6p")


for product in ${products[@]}
do
    status=`/usr/bin/curl -LI $prefixUrl$product -o /dev/null -w '%{http_code}' -s`
    if [ $status -eq '200' ]; then
        /usr/bin/curl -X POST --data-urlencode "payload={\"channel\": \"${channel}\", \"username\": \"${username}\", \"text\": \"${text}\", \"icon_emoji\": \"${iconemoji}\"}" ${webhookUrl}
        touch $doneFile
        exit 0
    fi
done

cronに仕込めば完成。
5分おきぐらいに実行すれば怒られないでしょう。
URLが下記のものであるだろうという予測を元に作ってあります。

https://store.google.com/product/nexus_5x
https://store.google.com/product/nexus_6p

ドキドキでしたが、このスクリプトを仕込んだ結果、ちゃんと通知されていました。

f:id:yuzurus:20150930151034p:plain

予約サイトがオープンした時間は日本時間AM2:20でした! この通知を見て無事予約できました。

iPhone7の予約サイトがオープンしたことをSlackに通知させたい

近い将来発売されるであろうiPhone7。
iPhone7の予約サイトがオープンしたことをSlackに通知させる場合は、先ほどのスクリプトを下記のように変更してください。

# サイトURL prefix
prefixUrl="http://www.apple.com/jp/shop/buy-iphone/"
# 製品名
products=("iphone7")

このスクリプトを仕込んだあなたは、きっと誰よりも早くiPhone7を手に入れる事ができるでしょう!

※URLを予測しているので、失敗したらごめんなさい。
※発表されるであろう日に仕込んでください。

ということでShell Script Advent Calendar 2015 8日目でした。
次は@ryoana14さんです。よろしくお願いします!

【PHP】たった1行コマンドを入力するだけでComposerを劇的に速くする方法【アジア圏限定】

f:id:yuzurus:20151129163147p:plain

PHPerで使っていない人はいないというぐらい、メジャーなPHPの依存管理ツールComposer。 ですが、動作が遅いという欠点があります。 Composerが遅い原因は主に下記だそうです。

  • packagist.orgが日本から遠い
  • composerのアーキテクチャ的に、小さなjsonファイルを少しずつダウンロードするため、ネットワークの遅延がもろに影響する
  • composerがfile_get_contentsでjsonをダウンロードしていて、どうやらKeep-Aliveを使っていないし、並列ダウンロードもしていない

Qiita

またある日@cakephperさんがこんなことを呟いていました。

そしたら、packagistのミラーサイト作ればいいんじゃね?と思い、作ろうと思っていたところ、すでに@hirakuさんが作っていたので、こっちに乗っかりました。

するとびっくり。composer爆速になりました。

packagistのミラーサイトをComposerへ導入する

下記のコマンドを打つだけで幸せになります

composer config -g repositories.packagist composer http://packagist.jp

packagist.jpを導入するにあたっての注意点

  • packagist.jpはpackagist.orgと1日1回同期しているようです。ほぼ最新ですが、ほぼという点をお忘れなく
  • packagist.jpはさくらVPS(日本)で運用しているため、爆速になるのはアジア圏でComposerを使った場合のみです
  • やはり元のリポジトリを参照したい、となったら下記のコマンドを打ってください
composer config -g --unset repositories.packagist

Validation::notEmpty() is deprecated. Use Validation::notBlank() instead.

CakePHPをバージョンアップしたら以下のエラーが表示されるようになった。

Validation::notEmpty() is deprecated. Use Validation::notBlank() instead.

該当のソースコードには以下の記載があった。

/**
 * Backwards compatibility wrapper for Validation::notBlank().
 *
 * @param string|array $check Value to check.
 * @return bool Success.
 * @deprecated 2.7.0 Use Validation::notBlank() instead.
 * @see Validation::notBlank()
 */
    public static function notEmpty($check) {
        trigger_error('Validation::notEmpty() is deprecated. Use Validation::notBlank() instead.', E_USER_DEPRECATED);
        return static::notBlank($check);
    }

CakePHP2.7からnotEmptyではなくnotBlankを使用しないといけないらしい。 notEmptyを叩くとnotBlankをそのまま呼び出しているので、すべて置換してよさそう。

これによると3.0.7以降は使えなくなる模様。 https://github.com/cakephp/cakephp/issues/6752

Node.jsのバージョンを管理するnodebrewを使ってみる

f:id:yuzurus:20151019173708p:plain

Node.jsを使う機会があったので簡単にNode.jsのバージョンを管理できるnodebrewを使ってみた。
自分の備忘録として。

nodebrewとは?

nodebrewとはNode.jsのバージョン切り替えを簡単に行えるツールです。
最近フロントエンド開発でNode.jsを使うことが当たり前になってきましたが、
Node.jsの開発が盛んで、プロジェクトごとにNode.jsのバージョンが違ったりすることが多いです。
その度にNode.jsを入れなおすのは面倒なので、nodebrewはそれを楽にしてくれます。

nodebrewのインストール

curl -L git.io/nodebrew | perl - setup

自分のbashrcやzshrcにパスを通す

export PATH=$HOME/.nodebrew/current/bin:$PATH

バージョンが表示されればOK

 nodebrew -v

nodebrewの使い方

使用できるバージョン一覧表示

nodebrew ls-remote

Node.jsのインストール

nodebrew install-binary v4.2.0

使用するNode.jsの設定

nodebrew use v4.2.0

Node.jsのバージョンを確認

node -v

v4.2.0と表示されればOK

インストールされているNode.jsのバージョン一覧確認

nodebrew ls

サーバサイドJavaScript Node.js入門 (アスキー書籍)

サーバサイドJavaScript Node.js入門 (アスキー書籍)

Vagrantの後継、Ottoを試してみた

f:id:yuzurus:20150930001342p:plain HashiCorpの新プロダクトOttoはVagrantの後継と位置づけられていて、開発環境だけでなく本番環境のデプロイまで視野にいれたコンセプトとなっているようです。
試しに使ってみたので、そのログを以下に記します。

Ottoのインストール

Ottoのダウンロードページからバイナリを落として、~/bin/以下に配置しました。

実際使ってみる

サンプルとしてRackアプリケーションがあるので、それを使ってみます。

前準備

$ git clone https://github.com/hashicorp/otto-getting-started.git
$ cd otto-getting-started
$ otto compile

 ~/dev/tmp/otto-getting-started ⮀ master ⮀ 5d18h51m ⮀  otto compile                                     ⮂
==> Loading Appfile...
==> No Appfile found! Detecting project information...
    No Appfile was found. If there is no Appfile, Otto will do its best
    to detect the type of application this is and set reasonable defaults.
    This is a good way to get started with Otto, but over time we recommend
    writing a real Appfile since this will allow more complex customizations,
    the ability to reference dependencies, versioning, and more.
==> Fetching all Appfile dependencies...
==> Compiling...
    Application:    otto-getting-started (ruby)
    Project:        otto-getting-started
    Infrastructure: aws (simple)

    Compiling infra...
    Compiling foundation: consul
==> Compiling main application...
==> Compilation success!
    This means that Otto is now ready to start a development environment,
    deploy this application, build the supporting infastructure, and
    more. See the help for more information.

    Supporting files to enable Otto to manage your application from
    development to deployment have been placed in the output directory.
    These files can be manually inspected to determine what Otto will do.

開発環境の構築

~/dev/tmp/otto-getting-started ⮀ master● ⮀ 5d18h51m ⮀ otto dev                                         ⮂
Would you like Otto to install Vagrant?
  An older version of vagrant was found installed (1.7.2). Otto requires
  version 1.7.4 or higher. Otto can install the latest version of vagrant
  for you (1.7.4). Would you like Otto to update vagrant for you?

  Please enter 'yes' to continue. Any other value will exit.

  Enter a value: yes

==> Downloading Vagrant v1.7.4...
    URL: https://dl.bintray.com/mitchellh/vagrant/vagrant_1.7.4.dmg

    85.3 MB/85.3 MB
[otto] Attaching Vagrant disk image...
[otto] Starting Vagrant installer...
Password:
installer: Package name is Vagrant
installer: Upgrading at base path /
installer: The upgrade was successful.
[otto] Vagrant installed. Cleaning up...
==> Vagrant installed successfully!
==> Creating local development environment with Vagrant if it doesn't exist...
    Raw Vagrant output will begin streaming in below. Otto does
    not create this output. It is mirrored directly from Vagrant
    while the development environment is being created.

Bringing machine 'default' up with 'virtualbox' provider...
==> default: Box 'hashicorp/precise64' could not be found. Attempting to find and install...
    default: Box Provider: virtualbox
    default: Box Version: >= 0
==> default: Loading metadata for box 'hashicorp/precise64'
    default: URL: https://atlas.hashicorp.com/hashicorp/precise64
==> default: Adding box 'hashicorp/precise64' (v1.1.0) for provider: virtualbox
    default: Downloading: https://atlas.hashicorp.com/hashicorp/boxes/precise64/versions/1.1.0/providers/virtualbox.box
==> default: Successfully added box 'hashicorp/precise64' (v1.1.0) for 'virtualbox'!
==> default: Importing base box 'hashicorp/precise64'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'hashicorp/precise64' is up to date...
==> default: Setting the name of the VM: dev_default_1443489702956_86673
==> 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:
    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 it's present...
    default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
    default: The guest additions on this VM do not match the installed version of
    default: VirtualBox! In most cases this is fine, but in rare cases it can
    default: prevent things such as shared folders from working properly. If you see
    default: shared folder errors, please make sure the guest additions within the
    default: virtual machine match the version of VirtualBox you have installed on
    default: your host and reload your VM.
    default:
    default: Guest Additions Version: 4.2.0
    default: VirtualBox Version: 4.3
==> default: Configuring and enabling network interfaces...
==> default: Mounting shared folders...
    default: /vagrant => /Users/yudsuzuk/dev/tmp/otto-getting-started
    default: /otto/foundation-1 => /Users/yudsuzuk/dev/tmp/otto-getting-started/.otto/compiled/app/foundation-consul/app-dev
==> default: Running provisioner: shell...
    default: Running: inline script
==> default: stdin: is not a tty
==> default: [otto] Installing Consul...
==> default: [otto] Installing dnsmasq for Consul...
==> default: [otto] Configuring consul service: otto-getting-started
==> default: Running provisioner: shell...
    default: Running: inline script
==> default: stdin: is not a tty
==> default: [otto] Adding apt repositories and updating...
==> default: [otto] Installing Ruby 2.2 and supporting packages...
==> default: [otto] Installing Bundler...
==> default: [otto] Configuring Git to use SSH instead of HTTP so we can agent-forward private repo auth...

==> Caching SSH credentials from Vagrant...
==> Development environment successfully created!
    IP address: 172.16.1.244

    A development environment has been created for writing a generic
    Ruby-based app.

    Ruby is pre-installed. To work on your project, edit files locally on your
    own machine. The file changes will be synced to the development environment.

    When you're ready to build your project, run 'otto dev ssh' to enter
    the development environment. You'll be placed directly into the working
    directory where you can run 'bundle' and 'ruby' as you normally would.

    You can access any running web application using the IP above.

SSH接続してRackアプリケーションを起動してみます。

otto dev ssh                                     ⮂
==> Executing SSH. This may take a few seconds...
Welcome to Ubuntu 12.04 LTS (GNU/Linux 3.2.0-23-generic x86_64)

 * Documentation:  https://help.ubuntu.com/
New release '14.04.3 LTS' available.
Run 'do-release-upgrade' to upgrade to it.

Welcome to your Vagrant-built virtual machine.
Last login: Fri Sep 14 06:23:18 2012 from 10.0.2.2
vagrant@precise64:/vagrant$ bundle && rackup --host 0.0.0.0
Fetching gem metadata from https://rubygems.org/..........
Fetching version metadata from https://rubygems.org/..
Installing rack 1.6.4
Installing rack-protection 1.5.3
Installing tilt 2.0.1
Installing sinatra 1.4.6
Using bundler 1.10.6
Bundle complete! 1 Gemfile dependency, 5 gems now installed.
Use `bundle show [gemname]` to see where a bundled gem is installed.
[2015-09-29 01:24:53] INFO  WEBrick 1.3.1
[2015-09-29 01:24:53] INFO  ruby 2.2.3 (2015-08-18) [x86_64-linux-gnu]
[2015-09-29 01:24:53] INFO  WEBrick::HTTPServer#start: pid=7107 port=9292

http://172.16.1.244:9292/ いけた。 f:id:yuzurus:20150930002003p:plain

本番環境の構築

AWS Access KeyとAWS Secret Keyが必要になるので予め準備しておいてください。

5d19h23m ⮀ otto infra                                       ⮂
==> Detecting infrastructure credentials for: otto-getting-started (aws)
    Cached and encrypted infrastructure credentials found.
    Otto will now ask you for the password to decrypt these
    credentials.

Encrypted Credentials Password
  Infrastructure credentials are required for this operation. Otto found
  saved credentials that are password protected. Please enter the password
  to decrypt these credentials. You may also just hit <enter> and leave
  the password blank to force Otto to ask for the credentials again.

  Enter a value:
    Existing infrastructure credentials were not found! Otto will
    now ask you for infrastructure credentials. These will be encrypted
    and saved on disk so this doesn't need to be repeated.

    IMPORTANT: If you're re-entering new credentials, make sure the
    credentials are for the same account, otherwise you may lose
    access to your existing infrastructure Otto set up.

AWS Access Key
  AWS access key used for API calls.

  Enter a value: 

AWS Secret Key
  AWS secret key used for API calls.

  Enter a value: 

SSH Public Key Path
  Path to an SSH public key that will be granted access to EC2 instances

  Default: ~/.ssh/id_rsa.pub
  Enter a value:

Password for Encrypting Credentials
  This password will be used to encrypt and save the credentials so they
  don't need to be repeated multiple times.

  Enter a value:
==> Building main infrastructure...
==> Executing Terraform to manage infrastructure...
    Raw Terraform output will begin streaming in below. Otto
    does not create this output. It is mirrored directly from
    Terraform while the infrastructure is being created.

    Terraform may ask for input. For infrastructure provider
    credentials, be sure to enter the same credentials
    consistently within the same Otto environment.

aws_vpc.main: Creating...
  cidr_block:                "" => "10.0.0.0/16"
  default_network_acl_id:    "" => "<computed>"
  default_security_group_id: "" => "<computed>"
  dhcp_options_id:           "" => "<computed>"
  enable_dns_hostnames:      "" => "1"
  enable_dns_support:        "" => "1"
  main_route_table_id:       "" => "<computed>"
  tags.#:                    "" => "1"
  tags.Name:                 "" => "otto"
aws_vpc.main: Creation complete
aws_key_pair.main: Creating...
  fingerprint: "" => "<computed>"
  key_name:    "" => "otto-d65180b2"
  public_key:  "" => "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDd5+GHOl+bLg8HLKtPOE0U3ar1YeX5XnuO+3riT73YSFK4OKkqqsngcVB1YUZGCrnreQ0GCi2rVR3L3maqlji2rNKvgZPqkC3tE7JgbN0b2OJhODdHauUFM74eKyEV6hKsw9qJI4LMKEMGgudoKpftQph6of3+A3gS+qd2WZHn8bkhMvYfrEucXXSHl3JMfCJ3kCgIBVYbaS2+6JP116vd65ZbLbR/hYLTWd6qwXkr2TO5YDoJ+UX7VRwnetSnot6ES0+tJcRNYxnNQpvNYpmyV8ZShLUM7UsxZ5R6P3lwO/J8CGvdDeYVzTh1ZFxsIp5r7P1GihsEfzbSMJu1Z1Xl yudsuzuk@yudsuzuk.local\n"
aws_internet_gateway.public: Creating...
  vpc_id: "" => "vpc-d65180b2"
aws_subnet.public: Creating...
  availability_zone:       "" => "<computed>"
  cidr_block:              "" => "10.0.2.0/24"
  map_public_ip_on_launch: "" => "1"
  tags.#:                  "" => "1"
  tags.Name:               "" => "public"
  vpc_id:                  "" => "vpc-d65180b2"
aws_key_pair.main: Creation complete
aws_internet_gateway.public: Creation complete
aws_route_table.public: Creating...
  route.#:                                   "" => "1"
  route.250069329.cidr_block:                "" => "0.0.0.0/0"
  route.250069329.gateway_id:                "" => "igw-dcf6c9b9"
  route.250069329.instance_id:               "" => ""
  route.250069329.network_interface_id:      "" => ""
  route.250069329.vpc_peering_connection_id: "" => ""
  tags.#:                                    "" => "1"
  tags.Name:                                 "" => "public"
  vpc_id:                                    "" => "vpc-d65180b2"
aws_subnet.public: Creation complete
aws_route_table.public: Creation complete
aws_route_table_association.public: Creating...
  route_table_id: "" => "rtb-405cda24"
  subnet_id:      "" => "subnet-b92032ce"
aws_route_table_association.public: Creation complete

Apply complete! Resources: 6 added, 0 changed, 0 destroyed.

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.

State path: /var/folders/nc/dg13cwg94xl7sq6rwvbdyy_h0000gn/T/otto-tf126060527/state

Outputs:

  infra_id      = d65180b2
  key_name      = otto-d65180b2
  region        = us-east-1
  subnet_public = subnet-b92032ce
  vpc_cidr      = 10.0.0.0/16
  vpc_id        = vpc-d65180b2

==> Terraform execution complete. Saving results...
==> Building infrastructure for foundation: consul
Get: file:///Users/yudsuzuk/dev/tmp/otto-getting-started/.otto/compiled/foundation-consul/deploy/module-aws-simple

==> Terraform execution complete. Saving results...
module.consul-1.aws_security_group.consul: Creating...
  description:                          "" => "Security group for Consul 1"
  egress.#:                             "" => "1"
  egress.482069346.cidr_blocks.#:       "" => "1"
  egress.482069346.cidr_blocks.0:       "" => "0.0.0.0/0"
  egress.482069346.from_port:           "" => "0"
  egress.482069346.protocol:            "" => "-1"
  egress.482069346.security_groups.#:   "" => "0"
  egress.482069346.self:                "" => "0"
  egress.482069346.to_port:             "" => "0"
  ingress.#:                            "" => "3"
  ingress.2541437006.cidr_blocks.#:     "" => "1"
  ingress.2541437006.cidr_blocks.0:     "" => "0.0.0.0/0"
  ingress.2541437006.from_port:         "" => "22"
  ingress.2541437006.protocol:          "" => "tcp"
  ingress.2541437006.security_groups.#: "" => "0"
  ingress.2541437006.self:              "" => "0"
  ingress.2541437006.to_port:           "" => "22"
  ingress.2547406835.cidr_blocks.#:     "" => "1"
  ingress.2547406835.cidr_blocks.0:     "" => "10.0.0.0/16"
  ingress.2547406835.from_port:         "" => "1"
  ingress.2547406835.protocol:          "" => "udp"
  ingress.2547406835.security_groups.#: "" => "0"
  ingress.2547406835.self:              "" => "0"
  ingress.2547406835.to_port:           "" => "65535"
  ingress.3910776171.cidr_blocks.#:     "" => "1"
  ingress.3910776171.cidr_blocks.0:     "" => "10.0.0.0/16"
  ingress.3910776171.from_port:         "" => "1"
  ingress.3910776171.protocol:          "" => "tcp"
  ingress.3910776171.security_groups.#: "" => "0"
  ingress.3910776171.self:              "" => "0"
  ingress.3910776171.to_port:           "" => "65535"
  name:                                 "" => "consul 1"
  owner_id:                             "" => "<computed>"
  vpc_id:                               "" => "vpc-d65180b2"
module.consul-1.aws_security_group.consul: Creation complete
module.consul-1.aws_instance.consul: Creating...
  ami:                               "" => "ami-7f6a1f1a"
  availability_zone:                 "" => "<computed>"
  ebs_block_device.#:                "" => "<computed>"
  ephemeral_block_device.#:          "" => "<computed>"
  instance_type:                     "" => "t2.micro"
  key_name:                          "" => "otto-d65180b2"
  placement_group:                   "" => "<computed>"
  private_dns:                       "" => "<computed>"
  private_ip:                        "" => "10.0.2.6"
  public_dns:                        "" => "<computed>"
  public_ip:                         "" => "<computed>"
  root_block_device.#:               "" => "<computed>"
  security_groups.#:                 "" => "<computed>"
  source_dest_check:                 "" => "1"
  subnet_id:                         "" => "subnet-b92032ce"
  tags.#:                            "" => "1"
  tags.Name:                         "" => "consul 1"
  tenancy:                           "" => "<computed>"
  vpc_security_group_ids.#:          "" => "1"
  vpc_security_group_ids.3140300483: "" => "sg-dea141b8"
module.consul-1.aws_instance.consul: Provisioning with 'file'...
module.consul-1.aws_instance.consul: Provisioning with 'remote-exec'...
module.consul-1.aws_instance.consul (remote-exec): Connecting to remote host via SSH...
module.consul-1.aws_instance.consul (remote-exec):   Host: 54.152.137.196
module.consul-1.aws_instance.consul (remote-exec):   User: ubuntu
module.consul-1.aws_instance.consul (remote-exec):   Password: false
module.consul-1.aws_instance.consul (remote-exec):   Private key: false
module.consul-1.aws_instance.consul (remote-exec):   SSH Agent: true
module.consul-1.aws_instance.consul (remote-exec): Connected!
module.consul-1.aws_instance.consul (remote-exec): consul stop/waiting
module.consul-1.aws_instance.consul (remote-exec): consul start/running, process 1356
module.consul-1.aws_instance.consul: Creation complete

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.

State path: /var/folders/nc/dg13cwg94xl7sq6rwvbdyy_h0000gn/T/otto-tf738944147/state

Outputs:

  consul_address = 10.0.2.6

==> Terraform execution complete. Saving results...
==> Infrastructure successfully created!
    The infrastructure necessary to deploy this application
    is now available. You can now deploy using `otto deploy`.

AMIイメージをotto buildコマンドからPackerで生成

 ~/dev/tmp/otto-getting-started ⮀ master● ⮀ 5d19h26m ⮀ otto build                                       ⮂
==> Detecting infrastructure credentials for: otto-getting-started (aws)
    Cached and encrypted infrastructure credentials found.
    Otto will now ask you for the password to decrypt these
    credentials.

Encrypted Credentials Password
  Infrastructure credentials are required for this operation. Otto found
  saved credentials that are password protected. Please enter the password
  to decrypt these credentials. You may also just hit <enter> and leave
  the password blank to force Otto to ask for the credentials again.

  Enter a value:
    Existing infrastructure credentials were not found! Otto will
    now ask you for infrastructure credentials. These will be encrypted
    and saved on disk so this doesn't need to be repeated.

    IMPORTANT: If you're re-entering new credentials, make sure the
    credentials are for the same account, otherwise you may lose
    access to your existing infrastructure Otto set up.

AWS Access Key
  AWS access key used for API calls.

  Enter a value: 

AWS Secret Key
  AWS secret key used for API calls.

  Enter a value: 

SSH Public Key Path
  Path to an SSH public key that will be granted access to EC2 instances

  Default: ~/.ssh/id_rsa.pub
  Enter a value:

Password for Encrypting Credentials
  This password will be used to encrypt and save the credentials so they
  don't need to be repeated multiple times.

  Enter a value:
Would you like Otto to install Packer?
  Otto requires packer to be installed, but it couldn't be found on your
  system. Otto can install the latest version of packer for you. Otto will
  install this into its own private data directory so it doesn't conflict
  with anything else on your system. Would you like Otto to install packer
  for you? Alternatively, you may install this on your own.

  If you answer yes, Otto will install packer version 0.8.6.

  Please enter 'yes' to continue. Any other value will exit.

  Enter a value: yes

==> Downloading packer v0.8.6...
    URL: https://dl.bintray.com/mitchellh/packer/packer_0.8.6_darwin_amd64.zip

    132 MB/132 MB
==> Unzipping downloaded package...
==> packer installed successfully!
==> Querying infrastructure data for build...
==> Building deployment archive...
==> Building deployment artifact with Packer...
    Raw Packer output will begin streaming in below. Otto
    does not create this output. It is mirrored directly from
    Packer while the build is being run.

otto output will be in this color.

==> otto: Prevalidating AMI Name...
==> otto: Inspecting the source AMI...
==> otto: Creating temporary keypair: packer 5609ef7b-f244-8dc1-8fe5-fb60911dd0f9
==> otto: Creating temporary security group for this instance...
==> otto: Authorizing access to port 22 the temporary security group...
==> otto: Launching a source AWS instance...
    otto: Instance ID: i-729290d1
==> otto: Waiting for instance (i-729290d1) to become ready...
==> otto: Waiting for SSH to become available...
==> otto: Connected to SSH!
==> otto: Provisioning with shell script: /var/folders/nc/dg13cwg94xl7sq6rwvbdyy_h0000gn/T/packer-shell137028228
==> otto: Uploading /Users/yudsuzuk/dev/tmp/otto-getting-started/.otto/compiled/app/foundation-consul/app-build/ => /tmp/otto/foundation-1
==> otto: Provisioning with shell script: /var/folders/nc/dg13cwg94xl7sq6rwvbdyy_h0000gn/T/packer-shell113570895
    otto: [otto] Installing Consul...
    otto: [otto] Installing dnsmasq for Consul...
    otto: [otto] Configuring consul service: otto-getting-started
==> otto: Uploading /var/folders/nc/dg13cwg94xl7sq6rwvbdyy_h0000gn/T/otto-slug-053371806 => /tmp/otto-app.tgz
==> otto: Provisioning with shell script: build-ruby.sh
    otto: [otto] Waiting for cloud-config to complete...
    otto: [otto] Adding apt repositories and updating...
    otto: [otto] Installing Ruby, Passenger, Nginx, and other packages...
    otto: [otto] Installing Bundler...
    otto: [otto] Extracting app...
    otto: [otto] Adding application user...
    otto: [otto] Setting permissions...
    otto: [otto] Configuring nginx...
    otto: [otto] Bundle installing the app...
    otto: Fetching gem metadata from https://rubygems.org/..........
    otto: Fetching version metadata from https://rubygems.org/..
    otto: Installing rack 1.6.4
    otto: Installing rack-protection 1.5.3
    otto: Installing tilt 2.0.1
    otto: Installing sinatra 1.4.6
    otto: Using bundler 1.10.6
    otto: Bundle complete! 1 Gemfile dependency, 5 gems now installed.
    otto: Gems in the groups development and test were not installed.
    otto: Bundled gems are installed into ./vendor/bundle.
    otto: [otto] ...done!
==> otto: Stopping the source instance...
==> otto: Waiting for the instance to stop...
==> otto: Creating the AMI: otto-getting-started 1443491707
    otto: AMI: ami-af2560ca
==> otto: Waiting for AMI to become ready...
==> otto: Terminating the source AWS instance...
==> otto: Cleaning up any extra volumes...
==> otto: No volumes to clean up, skipping
==> otto: Deleting temporary security group...
==> otto: Deleting temporary keypair...
Build 'otto' finished.

==> Builds finished. The artifacts of successful builds are:
--> otto: AMIs were created:

us-east-1: ami-af2560ca
==> Storing build data in directory...
==> Build success!
    The build was completed successfully and stored within
    the directory service, meaning other members of your team
    don't need to rebuild this same version and can deploy it
    immediately.

本番環境のデプロイ

otto deploy                                      ⮂
==> Detecting infrastructure credentials for: otto-getting-started (aws)
    Cached and encrypted infrastructure credentials found.
    Otto will now ask you for the password to decrypt these
    credentials.

Encrypted Credentials Password
  Infrastructure credentials are required for this operation. Otto found
  saved credentials that are password protected. Please enter the password
  to decrypt these credentials. You may also just hit <enter> and leave
  the password blank to force Otto to ask for the credentials again.

  Enter a value:
    Existing infrastructure credentials were not found! Otto will
    now ask you for infrastructure credentials. These will be encrypted
    and saved on disk so this doesn't need to be repeated.

    IMPORTANT: If you're re-entering new credentials, make sure the
    credentials are for the same account, otherwise you may lose
    access to your existing infrastructure Otto set up.

AWS Access Key
  AWS access key used for API calls.

  Enter a value:

AWS Secret Key
  AWS secret key used for API calls.

  Enter a value: 

SSH Public Key Path
  Path to an SSH public key that will be granted access to EC2 instances

  Default: ~/.ssh/id_rsa.pub
  Enter a value:

Password for Encrypting Credentials
  This password will be used to encrypt and save the credentials so they
  don't need to be repeated multiple times.

  Enter a value:
aws_security_group.app: Creating...
  description:                         "" => "Managed by Terraform"
  egress.#:                            "" => "1"
  egress.482069346.cidr_blocks.#:      "" => "1"
  egress.482069346.cidr_blocks.0:      "" => "0.0.0.0/0"
  egress.482069346.from_port:          "" => "0"
  egress.482069346.protocol:           "" => "-1"
  egress.482069346.security_groups.#:  "" => "0"
  egress.482069346.self:               "" => "0"
  egress.482069346.to_port:            "" => "0"
  ingress.#:                           "" => "1"
  ingress.482069346.cidr_blocks.#:     "" => "1"
  ingress.482069346.cidr_blocks.0:     "" => "0.0.0.0/0"
  ingress.482069346.from_port:         "" => "0"
  ingress.482069346.protocol:          "" => "-1"
  ingress.482069346.security_groups.#: "" => "0"
  ingress.482069346.self:              "" => "0"
  ingress.482069346.to_port:           "" => "0"
  name:                                "" => "otto-getting-started-d65180b2"
  owner_id:                            "" => "<computed>"
  vpc_id:                              "" => "vpc-d65180b2"
aws_security_group.app: Creation complete
aws_instance.app: Creating...
  ami:                               "" => "ami-af2560ca"
  availability_zone:                 "" => "<computed>"
  ebs_block_device.#:                "" => "<computed>"
  ephemeral_block_device.#:          "" => "<computed>"
  instance_type:                     "" => "t2.micro"
  key_name:                          "" => "otto-d65180b2"
  placement_group:                   "" => "<computed>"
  private_dns:                       "" => "<computed>"
  private_ip:                        "" => "<computed>"
  public_dns:                        "" => "<computed>"
  public_ip:                         "" => "<computed>"
  root_block_device.#:               "" => "<computed>"
  security_groups.#:                 "" => "<computed>"
  source_dest_check:                 "" => "1"
  subnet_id:                         "" => "subnet-b92032ce"
  tags.#:                            "" => "1"
  tags.Name:                         "" => "otto-getting-started"
  tenancy:                           "" => "<computed>"
  vpc_security_group_ids.#:          "" => "1"
  vpc_security_group_ids.3738479127: "" => "sg-45a94923"
aws_instance.app: Creation complete

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.

State path: /var/folders/nc/dg13cwg94xl7sq6rwvbdyy_h0000gn/T/otto-tf489279237/state

Outputs:

  url = http://ecXXXXXXXXXXXXXXXX.compute-1.amazonaws.com/

アクセスしてみる。 f:id:yuzurus:20150930002525p:plain いけた。

まとめ

まだ機能は少ないですが、今後のOttoの発展に期待です。