suguru.dev

バンクーバーで働くエンジニアの備忘録

Google Cloud Platform上にContainer Clusterを作成する

概要

Google Cloud PlatformのContainer Cluster(Kubernetes)のセットアップからデプロイまでの手順です。プロジェクトの作成手順は省略します。

Container Clusterの作成

メニューから [Container Engine] -> [Container Clusters] を開き、[CREATE CLUSTER]をクリック。必要な項目を有効にして作成してください。 このプロジェクトではCloud SQLを利用しているので、Cloud SQLをEnabledにしています。

作成後、画面にConnectと出てくるので、メニューに従って実行します。

$ gcloud container clusters get-credentials production \
    --zone {指定したzone} --project {project-id}
$ kubectl proxy

gcloudのSDKはこちらからダウンロード可能です。

Cloud SDK  |  Google Cloud Platform

installの際にインストール不足のものはエラーとして表示されるので、それに従ってinstallして再度上のコマンドを実行すれば完了です。

http://localhost:8001/ui/にアクセスしKubernetesの画面が見れれば準備は完了です。

Redisのデプロイ

プロジェクトでredisを使用しているためredisのDockerイメージをデプロイします。Dockerをinstallしていない方はこちらからインストールできます。

Installation on Mac OS X

$ docker pull redis:alpine
$ docker tag redis:alpine gcr.io/{project-id}/redis:alpine
$ gcloud docker push gcr.io/{project-id}/redis:alpine

これでRedisのデプロイは完了です。

コンテナの配置

後は先程のブラウザ上でコンテナを配置するだけです。

f:id:suguru03:20160930145803p:plain

右上の[CREATE]をクリックし、必要に応じて入力してください。コンテナイメージのパスは [Compute Engine] -> [VM instances] のところのInstance templeteをコピペすれば完了です。 ポッド数は必要に応じて増やしてください。また今回のRedisは外部アクセスを許可していないので内部アクセスのみにしてあります。

他にNode.jsのDocker Imageもデプロイしましたがまた別の機会に作成手順と一緒に書きたいと思います。

感想

Docker & Kubernetes初日でしたが、同僚の手助けの下、数時間でNode.js/Redis Clusterの動作確認ができました。とても便利なので今後も使っていきたいです。

ソース

Pokemon Goのちょっと得する情報

カナダで一足先にプレイしています。ポケモン効果はすごいです、家から基本出なかったカナディアンの友達が毎日外出してます。

さて色々損してきたのでさくっと箇条書きでまとめときます。

  • ピカチュウをゲットする
    • 最初の三匹を選ばずに待っていると現れます。
  • サークルは小さいほうが捕まえやすい
  • サークル内にヒットすると捕まりやすくなるのと経験値がもらえる
  • 足あとは少ないほど近い
  • Lv30までは「ほしのすな」・「アメ」は使わない
    • 育てたとしても野生で同じ強さ・もしくはそれ以上のポケモンが出てきます。
    • 育てても無駄です。
    • 個体値があるようなので、個体値MAXのポケモンは無駄ではないかも。(*追記 6/23)
  • 卵のレベル上限はLv20
  • 卵の内訳
  • 有料ボックスは5km以上の卵に使ったほうがコスパいい
    • 2kmは無限ボックスで孵化させましょう。
  • Lv上限は現在40
  • イーブイの進化のさせ方 (アニメ参照)
    • リネームする (最初は大文字だよ、日本語対応してるかわからない)
      • Sparkyが欲しい場合Jolteon
      • Vaporeonが欲しい場合Rainer
      • Flareonが欲しい場合Pyro
    • 再起動する
    • 進化させる
  • ズバット
    • 玉の浪費なので高CPは逃げる
    • カーブが気持ち射程長い気がしないでもない
  • カーブはボールをくるくるすれば投げられる
  • ラズベリーポケモンが逃げにくくなる
    • レアポケモンに使いましょう
    • ボールを投げるごとにあげましょう
  • ボールを投げた後にフリーズする
    • いくら待っても結果は変わりません、再起動してください。
  • googleアカウントをカナダにしてカナダドルでクレカ切るとお得
    • 14,500コインでおそらく1,200円くらいお得ですかね(81円換算)
  • Lure moduleのピンクのところをクリックするとアイテム使ってくれてる人がわかる
    • 見てあげてください
  • 個体値 *追記 6/23
    • サイズがでかいほうが高い
    • 進化はギリギリまでさせてはいけない
  • ポッポマラソン *追記 6/23
    • ポッポの入手が簡単
    • 進化させると経験値が入る
    • しあわせタマゴで経験値2倍
  • ミューツー、ファイヤー、サンダー、フリーザーは伝説
  • ミュウは(ry

Have a good Pokemon life!

リンク

GAEからCloud Storageに画像をアップロードする

はじめに

Google App Engine (GAE)のGolangAPI仕様がガラッと変わったようなので、古いバージョンを使っている方はここを参考に書き換えてください。

GitHub - golang/appengine: Go App Engine packages

Goのversionは1.6.2を使用しています。

画像のアップロード

実際はリクエストを受け取り、その画像をCloud Storageにアップロードしていますが、 実行しやすいようにローカルファイルとテストを使用しています。

package storage

import (
    "fmt"
    "google.golang.org/appengine"
    "google.golang.org/appengine/aetest"
    "google.golang.org/appengine/blobstore"
    "google.golang.org/appengine/image"
    "google.golang.org/appengine/log"
    "google.golang.org/cloud/storage"
    "io"
    "net/http"
    "os"
    "testing"
)

const (
    bucket = "<bucket path>"
    image = "<image path>"
)

func Upload(req *http.Request) (string, error) {
    ctx := appengine.NewContext(req)
    client, err := storage.NewClient(ctx)
    file, err := os.Open(image)
    userName := "tester"
    fileName := "test.jpg"
    mimeType := "image/jpeg"
    filePath := fmt.Sprintf("%s/%s", userName, fileName)
    blobWriter := client.Bucket(Bucket).Object(filePath).NewWriter(ctx)
    blobWriter.ContentType = mimeType
    io.Copy(blobWriter, file)
    err = blobWriter.Close()
    blobPath := fmt.Sprintf("/gs/%s/%s", Bucket, filePath)
    blobKey, err := blobstore.BlobKeyForFile(ctx, blobPath)

    // crop
    opts := image.ServingURLOptions{Secure: false, Crop: true}
    url, err := image.ServingURL(ctx, blobKey, &opts)
    log.Infof(ctx, "url", url)
    return url.String(), err
}

func TestUpload(t *testing.T) {
    inst, err := aetest.NewInstance(nil)
    req, err := inst.NewRequest("GET", "/gophers", nil)
    url, err := Upload(req)
    fmt.Printf("test", url, err)
}

ローカルで実行すると画像は正常にアップロードされますが、ServingURLがうまく働いてくれないようでhttp://localhost/_ah/img/encoded_gs_file:...のようなパスになってしまいます。 GAE上だと正常に動いているのですがテストを書く上でとても不便ですね。。

Image.Decodeでunknown formatになったときの対処法

いまいち条件がわかりませんが、一度Decodeされたデータは再度Decodeしようとするとunknown formatになるようです。 Goのバージョンは1.6.2を使用しています。 依存ファイルは以下のとおりです。

import (
    "bytes"
    "image"
    "image/gif"
    "image/jpeg"
    "image/png"
    "io"
    "os"
)

ダメな例

まずはダメな例です。

file, _ := os.Open("./image.jpg")
img, _ := jpeg.Decode(file)
conf, encode, err := image.DecodeConfig(file) // unknown format

DecodeでもDecodeConfigでも再現します。これは困ります。

対処法1

ファイルを開き直すことで解決します。

file, _ := os.Open("./image.jpg")
img, _ := jpeg.Decode(file)
file, _ = os.Open("./image.jpg")
conf, encode, err := image.DecodeConfig(file)

気持ち悪いです。

対処法2

別の方法を模索したところ、EncodeしてDecodeし直すと解決することがわかりました。

file, _ := os.Open("./image.jpg")
img, _ := jpeg.Decode(file)
buf := new(bytes.Buffer)
jpeg.Encode(buf, img, nil)
conf, encode, err := image.DecodeConfig(file)

気持ち悪さは半減しましたが、まだ気持ち悪いです。

対処法3

事前にいじれる場合はio.Copyでコピーすると良さそうです。

file, _ := os.Open("./image.jpg")
buf := new(bytes.Buffer)
io.Copy(buf, file)
img, encode, _ := image.Decode(file)
conf, encode, err := image.DecodeConfig(buf)

まとめ

最終的にio.Copyに落ち着きました。

func Decode(file io.Reader) {
    buf := new(bytes.Buffer)
    io.Copy(buf, file)
    img, encode, err := image.Decode(file)
    conf, encode, err := image.DecodeConfig(buf)
    ...
}

ソース

Benchmark: Async vs Neo-Async

What is Neo-Async?

Neo-Async is meant to be used as a drop-in replacement for the Async library. It implements the same API, and adds extra functionality. I have been trying to make it faster and safer than Async.

https://github.com/suguru03/neo-async

It doesn't mean I don't like Async. I would like to improve both libraries and to showcase some performance optimizations that might be implemented by other Node.js libraries. I especially admire @aearly for their good work.

Benchmark

Recently, Async has been released v2.0.0-rc.6 and I released Neo-Async v2.0.0-rc.1.
So I would like to check performance using benchmark and func-comparator.

How to check

I made a repository to measure performance between Async and Neo-Async.

https://github.com/suguru03/async-benchmark

$ git clone git@github.com:suguru03/async-benchmark.git
$ cd async-benchmark
$ npm install
$ node . // It might take more than one hour... 

Environment

  • Ubuntu v12.04
  • Node.js v6.2.1
  • async v2.0.0-rc.6
  • neo-async v2.0.0-rc.1
  • benchmark v2.1.0
  • func-comparator v0.7.1

Result

Neo-Async is 1.27 ~ 10.7 times faster than Async.

The value is the ratio (Neo-Async/Async) of the average speed.

Collections

function benchmark func-comparator
each 3.71 2.54
eachSeries 2.14 1.90
eachLimit 2.14 1.88
eachOf 3.30 2.50
eachOfSeries 1.97 1.83
eachOfLimit 2.02 1.80
map 4.20 4.11
mapSeries 2.40 3.65
mapLimit 2.64 2.66
mapValues 5.71 5.32
mapValuesSeries 3.82 3.23
mapValuesLimit 3.10 2.38
filter 8.11 8.76
filterSeries 5.79 4.86
filterLimit 4.00 3.32
reject 9.47 9.52
rejectSeries 7.39 4.64
rejectLimit 4.54 3.49
detect 6.67 6.37
detectSeries 3.54 3.73
detectLimit 2.38 2.62
reduce 4.13 3.23
reduceRight 4.23 3.24
transform 5.30 5.17
sortBy 2.24 2.37
some 6.39 6.10
someSeries 5.37 4.66
someLimit 3.39 2.84
every 6.85 6.27
everySeries 4.53 3.90
everyLimit 3.36 2.75
concat 9.18 9.35
concatSeries 7.49 6.09

Control Flow

funciton benchmark func-comparator
parallel 7.54 5.45
series 3.29 2.41
waterfall 5.12 4.27
whilst 1.96 1.95
doWhilst 2.07 1.96
until 2.10 1.99
doUntil 1.98 2.04
during 10.7 7.09
doDuring 5.98 6.03
queue 1.83 1.75
priorityQueue 1.79 1.75
times 3.84 3.65
race 1.45 1.27
auto 3.23 3.50
retry 9.43 6.78

Future Prospects

I'm not done with performance optimization; the control flow functions are my main focus right now. I will release v2.0.0 when satisfied with performance.

And I'm keeping in mind this issue.

Benchmark setup seems to be biased against async callback style libraries · Issue #985 · petkaantonov/bluebird · GitHub

I believe the asyncFlowF library doesn't implement the same interface as Async, but I would like Neo-Async to be beat it benchmark anyways. ;) Even as many JavaScript users switch to Promises, callback style is far from dead, so I want to keep improving Async and Neo-Async.

Next time, I will write about the difference between Async and Neo-Async. :)

Reference

Golang始めました

始めたきっかけ

Node.jsエンジニアとして採用されましたが、Node.js/Go/Javaの3つのサーバが建っていたため、最近ではGoのコードも修正したりしてます。

導入

Node.js出身の僕としては、やはりnvmのようなパッケージ管理モジュールを入れたいものです。gvm、gobrewというモジュールがありますが、よく使われてそうなgvmには最新バージョンが入っていなかったためgobrewを使ってみることにしました。

GitHub - moovweb/gvm: Go Version Manager

GitHub - cryptojuice/gobrew: Shell script to download and set GO environmental paths to allow multiple versions.

gobrewの設定

gobrewをダウンロードします。

$ git clone git://github.com/cryptojuice/gobrew.git ~/.gobrew

次に.bashrcまたは.zshrcに追加します。

GO_VERSION=1.6.2
export PATH=$HOME/.gobrew/bin:$PATH
eval "$(gobrew init -)"
gobrew use $GO_VERSION
ECHO "Now using golang $GO_VERSION"

nvm好きの僕としては最後の一行だけは忘れずに追加していただきたいものです。

後はインストールするだけです。

$ gobrew install 1.6.2
$ gobrew use 1.6.2

以上です。

$GOPATHの設定

実際に使用する際は、作業ディレクトリに移動し$GOPATHを設定します。

$ gobrew workspace set

またnvm同様、

$ gobrew use {VERSION}

と簡単にバージョンを変えられるのでとても便利です。

ソース

GitHub - cryptojuice/gobrew: Shell script to download and set GO environmental paths to allow multiple versions.