oinume journal

Scratchpad of what I learned

GCPのCloud Runを使って簡単なリダイレクタを作った話

今年5月にbetaとしてリリースされたGCPのCloud Runを使って、もともとGAEで運用していたリダイレクタを移植してみたのでその紹介。

Cloud Runとは

HTTPリクエストを処理するためのFull ManagedなステートレスのContainerの実行環境。公式サイトには以下のように説明されている。

Cloud Run is a managed compute platform that enables you to run stateless containers that are invocable via HTTP requests

GCPでは、Full Managedな実行環境(PaaS)として

  • Google App Engine(Standard Edition)
  • Cloud Functions

が存在しているが、完全にContainerベースのCloud Runが新しく追加されたよ、という風に自分は認識している。

リダイレクタの詳細

というだけのもの。実際にはURLごとにリダイレクト先が異なるのでプログラムを書いている。もともとはGAE Standard Editionで動かしていた。

準備

  • GCPのプロジェクトを作る
  • gcloud components update を実施する
  • gcloud components beta を実施する
  • Cloud RunのRegionを設定する
    • gcloud config set run/region us-central1
  • Cloud Buildを有効にする
  • Container Registryを有効にする

Cloud Runで実行するコード

実際にCloud Runで実行するコードは以下のような感じ

Dockerfile

Cloud RunはContainerを実行するので、Dockerfileを用意する。やっていることは ./cmd/server/main.go をコンパイルして server というバイナリを生成しているだけ。

Cloud BuildでContainer Imageをdeployする

自動化も加味して、CircleCIからContainer Imageを生成してGCRにdeployするようにしてみる。CircleCIのconfig.ymlはこんな感じ。

実際は Makefile で実行しているのは以下のコマンドになる。

$ gcloud builds submit --project ${GCP_PROJECT_ID} \
  --tag gcr.io/$(GCP_PROJECT_ID)/server:${IMAGE_TAG}
  • GCP_PROJECT_ID: あなたのGCPのプロジェクトID
  • IMAGE_TAG: master-123 のような値になっている。CircleCI上でビルドするので IMAGE_TAG=$(echo "${CIRCLE_BRANCH}" | tr '._/' '-' | tr '[:upper:]' '[:lower:]')-"${CIRCLE_BUILD_NUM}" としている。ただこれはもっと良い生成方法があるかもしれない。

なお、CircleCIからgcloud buildsでGCRにimageをpushするときに以下のエラーが発生してハマった。

Uploading tarball of [.] to [gs://blog-lampetty-net-redirector_cloudbuild/source/1557916060.04-0e599d9522c1400ebb47e942a96cb9b2.tgz]
Created [https://cloudbuild.googleapis.com/v1/projects/blog-lampetty-net-redirector/builds/ec22748d-e4c6-4e10-ba89-f4e108cac0d8].
Logs are available at [https://console.cloud.google.com/gcr/builds/ec22748d-e4c6-4e10-ba89-f4e108cac0d8?project=310764868638].
ERROR: (gcloud.builds.submit) HTTPError 403: <?xml version='1.0' encoding='UTF-8'?><Error><Code>AccessDenied</Code><Message>Access denied.</Message><Details>circle-ci@blog-lampetty-net-redirector.iam.gserviceaccount.com does not have storage.objects.get access to 310764868638.cloudbuild-logs.googleusercontent.com/log-ec22748d-e4c6-4e10-ba89-f4e108cac0d8.txt.</Details></Error>

解決方法としてはここにあるように、Project ViewerのRoleをService Accountに対して付与しないといけない。もしくは、cloudbuild.yamlの設定で logsBucket を指定してここへのロールを追加すれば良い。

CircleCIからgcloudコマンドで最新のcontainer imageをCloud Runに反映する

これはまだ自動化していない。以下のコマンドで自分のマシンからCloud Runに反映している。

$ gcloud beta run deploy --project ${GCP_PROJECT_ID} --image gcr.io/${GCP_PROJECT_ID}/server:${IMAGE_TAG}

Service name (server):
Deploying container to Cloud Run service [server] in project [${GCP_PROJECT_ID}] region [us-central1]
✓ Deploying... Done.
  ✓ Creating Revision...
  ✓ Routing traffic...
Done.
Service [server] revision [server-00005] has been deployed and is serving traffic at https://xyz.a.run.app

コマンドを実行すると最後に表示される https://xyz.a.run.app がアプリケーションが動いているURLである。

独自ドメインの割り当て

Cloud Runによって自分のアプリケーションに割り当てられたURLを独自ドメインに変更することができる。以下のコマンドを使うか、Consoleから設定ができる。

$ gcloud beta run domain-mappings create

プログラマのためのGoogle Cloud Platform入門 サービスの全体像からクラウドネイティブアプリケーション構築まで

プログラマのためのGoogle Cloud Platform入門 サービスの全体像からクラウドネイティブアプリケーション構築まで

参考リンク

2019年3月の振り返り

アウトプット

GCPのCloud PubSubをGoで動かしてみただけのメモ のみ。とにかく仕事が忙しくてプライベートで勉強したり何かをアウトプットすることを疎かにしてしまった(おかげで仕事は捗った)。

英語

3月から会社がDMM英会話から試験的にNativeCampに切り替えたため1回しかレッスンを受けなかった。単語もiKnowを使っていたのだけど、DMM英会話がストップされた影響で使えなくなってやらなくなってしまった。4月からはまたDMM英会話に戻ったのでちゃんと再開する予定。

アルゴリズム

グラフはやりかけで放置してしまっている。

スマートウォッチ

Fitbit Charge3が微妙だったのでいったんPebbleに戻していたけど、Fitbit Versa Liteなるものが発売されたのでこれを買ってみた。やっぱりPebbleの方が使いやすいとは思いつつ、基本機能は満足しているのでこれを使っていこうかなと思っている。一番良いのは心拍数が測れるところ。ウォーキングやジョギングで頑張りすぎないようにペースを調節したり、逆にまだまだいけそうだと思ったらペースを上げたりする目安になっている。

読んだ本

Googleを支える技術

全部読んだわけではないけどGoogleのシステムの内部について詳細にわかりやすく書かれている良い本。初期のGoogle検索エンジンのシステムの内部構成がわかりやすく解説されていて、「おっこれなら自分でも作れるのでは?」と思うぐらいに理解ができた。

Googleを支える技術 ……巨大システムの内側の世界 WEB+DB PRESS plus

Googleを支える技術 ……巨大システムの内側の世界 WEB+DB PRESS plus

脳を鍛えるには運動しかない!

まだ読んでいる途中だけど、脳細胞を活性化させるために運動が必要だと説く本。アメリカの小学校では、授業の前に朝一で運動することで学力が上がったという話を皮切りに運動が脳に与えるプラスの効果について延々と書かれている本。これを読んで、自分も出勤前にジムに行くように心がけるようになった。

脳を鍛えるには運動しかない!  最新科学でわかった脳細胞の増やし方

脳を鍛えるには運動しかない! 最新科学でわかった脳細胞の増やし方

  • 作者: ジョン J.レイティ,エリックヘイガーマン,John J. Ratey,Eric Hagerman,野中香方子
  • 出版社/メーカー: NHK出版
  • 発売日: 2009/03/20
  • メディア: 単行本(ソフトカバー)
  • 購入: 31人 クリック: 757回
  • この商品を含むブログ (75件) を見る

GCPのCloud PubSubをGoで動かしてみただけのメモ

これはGCPのCloud PubSubのチュートリアルをやってみただけの自分用のメモ。この記事で紹介されているサンプルコードはGitHubに置いてある。

Cloud PubSubとは

GCPで提供されているメッセージキュー。メッセージの送信をして(publish)、複数のシステムがそのメッセージを受信(subscribe)することができる。

登場する概念

  • Message: PubSubを通じて送受信したいメッセージ
  • Publisher: Messageを生成しTopicに送るもの
  • Topic: Messageの送信先
  • Subscription: Topicに対して紐付けられるMessageを受信するもの。1つのTopicに対して複数のSubscriptionを設定することができる
  • Subscriber: Subscriptionと関連付けられた、Messageを受信するシステム

詳細はドキュメントに書いてある。

イメージ

使ってみる

APIを有効にする

gcloud services listで検索して

$ gcloud config set project oinume-pubsub-sample
$ gcloud services list --available | grep pubsub
pubsub.googleapis.com Cloud Pub/Sub API

enableで有効にする。

$ gcloud services enable pubsub.googleapis.com
Operation "operations/acf.dd53c399-e6be-48c3-a087-ff01c982d0d8" finished successfully.

Topicの作成

first-topic という名前のTopicを作る。

$ gcloud pubsub topics create first-topic
Created topic [projects/oinume-pubsub-sample/topics/first-topic].

Subscriptionの作成

first-topic へのSubscriptionを作る。SubscriptionはPull型とPush型の2つの種類があるが、今回はPush型を使っている。この2つについて詳しく知りたい場合はドキュメントを参照。--push-endpoint の詳細については次で説明する。

$ gcloud pubsub subscriptions create first-topic-subscription \
—topic first-topic \
—push-endpoint="https://oinume-pubsub-sample.appspot.com/_ah/push-handlers/first-topic“

Google App Engineでpush型のsubscriberを作る

先ほど --push-endpoint で指定したendpointをGAEで実装してみる。これはPubSubのmessageがpublishされたときにGCPから呼ばれるもの。GitHubにコードを上げてあるが、 "/_ah/push-handlers/first-topic のURLのHandlerを定義して、標準出力に来たmessageを出力するだけのコードである。

main.go

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "os"
)

func main() {
    http.HandleFunc("/", indexHandler)
    http.HandleFunc("/_ah/push-handlers/first-topic", pushHandler)

    port := os.Getenv("PORT")
    if port == "" {
        port = "8080"
        log.Printf("Defaulting to port %s\n", port)
    }

    log.Printf("Listening on port %s", port)
    log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path != "/" {
        http.NotFound(w, r)
        return
    }
    fmt.Fprint(w, "Hello, World!!")
}

func pushHandler(w http.ResponseWriter, r *http.Request) {
    type pushRequest struct {
        Message struct {
            Attributes map[string]string
            Data       []byte
            ID         string `json:"message_id"`
        }
        Subscription string
    }

    message := &pushRequest{}
    if err := json.NewDecoder(r.Body).Decode(message); err != nil {
        log.Printf("Could not decode body: %v\n", err)
        http.Error(w, fmt.Sprintf("Could not decode body: %v", err), http.StatusBadRequest)
        return
    }

    log.Printf("Data = %v\n", string(message.Message.Data))
    fmt.Fprint(w, "ok")
}

messageをpublishしてみる

以下のような感じでpublisherを実行すると first-topic にmessageがpublishされる。 oinume-pubsub-sample は自身のGCPプロジェクト名に置き換えること。

$ export GOOGLE_CLOUD_PROJECT=oinume-pubsub-sample
$ export GO111MODULE=on
$ go run cmd/publisher/publisher.go first-topic "Hello world"

実際にmessageのsubscribeが成功したかどうかはGCPのStackdriver Loggingで見ることができる。

疑問

  • push-handlerがHTTPで200以外を返した場合、どのぐらいのタイミングで再送される?
  • 再送する回数の上限は指定できる?

プログラマのためのGoogle Cloud Platform入門 サービスの全体像からクラウドネイティブアプリケーション構築まで

プログラマのためのGoogle Cloud Platform入門 サービスの全体像からクラウドネイティブアプリケーション構築まで

2019年02月の振り返り

アウトプット

特になし

英語

1月とほぼ変わらずという状態。ふと、2年前ぐらいに受けたTOEICの結果を見ていたら、Readingにおいて自分は単語力が弱いと書かれていたので、単語をちゃんと勉強するのが一番効果的っぽい。なお、今まで会社の補助で使えていたDMM英会話が使えなくなり途方にくれている。

アルゴリズム

やっとBTreeを実装した。写経していたはずが、些細なバグに悩まされ時間がかかってしまったけどやっと実装できてよかった。この記事をおおいに参考にさせてもらった。多謝。

来月はグラフをやる。

Fitbit Charge3

時計をPebble TimeからFitbit Charge3に変えた。のだけど、Pebbleに比べてFitbitが微妙過ぎてつらい。

  • 時計盤が常に表示されているわけではないので、時刻を見たい時は常に腕を回す動作をしないといけない。場合によってはこれでも表示されないので、わざわざ画面をタップしないといけない。
    • これはいろいろ調べたけど設定変更で直せるものではないっぽいぞ... Pebbleは常に表示されていたので良かった。
  • 通知のバイブレーションが微妙。通知が連続できたのか、それとも電話が鳴っていているのかバイブのパターンではわからない。
  • 自転車に乗っている時でも歩いたことになっているようでステップ数がカウントされているっぽい
    • これはまだちゃんと確認してない
  • 標準のFitbitアプリからiOSのヘルスケアにデータを同期してくれない。

というわけでPebbleの完成度の高さをあらためて知るのであった。Pebble自体は会社がFitbitに買収されてディスコンなんだけど、Pebble2あたりを買い直そうか真剣に悩んでいる。

楽天銀行のデビットカードはいいぞ

最近メインバンクを三菱UFJから楽天銀行に移している。現在進行系なのは、様々な引き落としの手続きに時間がかかっているためだけど、近日中には終わると思う。

デビットカードってなに?メリットは?

使うときはクレジットカードと同じように使える。例えばVISAブランドのデビットカードであればVISAの加盟店であればどこでも使える。クレジットカードみたいに請求が遅れてくることがないため、「気づいたら今月30万もクレカで使っていた」というようなことが起きにくい。また、銀行が発行するデビットカードはたいていキャッシュカードとの一体型になっているので、クレカとキャッシュカードの2枚持ちに終止符を打つことができる。デビットカードではなくクレジットカードを使いたい場合、楽天銀行のキャッシュカードと一体型のものも存在するのでこれを使うのもいいかもしれない。

また、ほとんどの銀行においてクレジットカードのような審査がないという点も大きなメリットの一つだと思う。収入が少ない学生や定職についてない人などは審査がないことは大きなメリットのはず。

なぜ楽天銀行なの?

  • 楽天ポイントがつく。そして獲得したポイントをデビットカードでの支払いに使うことができる
  • もともと楽天カードを使っていた
  • ATM引き出しの手数料や振込手数料が無料になる条件が三菱UFJに比べると緩い
    • 楽天銀行の場合: 給与振り込み口座にするとそれだけで他行への振込手数料が3回無料になる
    • 預ける資産が300万円以上でATM利用手数料7回無料、他行振込手数料が3回無料になる。
    • 三菱UFJの場合は、預ける資産が500万円以上ではないとATM手数料や振込手数料が無料にならない
  • (これは楽天銀行だけではなくネット銀行のメリットだけど)印鑑とか紙の通帳から開放されたかった

実際どうなのか?

良いところ

  • クレジットカードだと明細に残るまでに数日から数週間のタイムラグがあるが、デビットカードだとそれがないのがやっぱりいい
  • あとは楽天ポイントをデビットカード利用時に使えること。

不便なところ

  • デビットカードで決済すると、リアルタイムに自分の銀行口座から引き落としされるんだけど、明細には「どの店で利用したか」という情報が残らないっぽい。なので、マネーフォワードと連携していても「この5000円何に使ったんだっけ?」というのがわかりづらい。
  • マネーフォーワードと連携する場合、クレカであれば単純に支出が記録されるだけだが、銀行口座の連携の場合は他の口座への振替や現金引き出しも連携されてデータが残ってしまうので、マネーフォーワードで都度計算対象から外すのが面倒

というのが感じているところ。まぁ我慢できる範囲かなと思ってこの2つに関しては諦めている。

さいごに

メガバンクは早く淘汰されてほしいので、ネット銀行に移行しよう(煽り)

学校では教えてくれない大切なこと3お金のこと

学校では教えてくれない大切なこと3お金のこと