tjun月1日記

なんでもいいので毎月書きたい

mercariのtech blog書いた

はじめて投稿しました。

tech.mercari.com

もとは、Microservices PlatformのMeetupで発表した内容です。

本当はもうちょっといろいろ書きたかったのですが、間に合いませんでした。

より詳しい話は、 CloudNative Days TokyoGoogle Cloud Next Tokyoで発表する予定です、よろしくおねがいします。

Fastly meetup #2でLTしてきた

2019/04/16のFastly Meetup#2 でLTしてきました。枠が余っていたので、2つ。

一つは、Fastlyのメトリクスやログをどのように監視、調査しているかについて、もう一つはKubernetes上のNode.jsのmicroserviceアプリケーション with nginxで画像を配信したときに、404が意図せずFastlyでキャッシュされてしまった問題について話しました。

2018振り返り

年越したけど久しぶりに更新します。

書いてたら長くなっちゃんたんで、めっちゃ省略して書きます。

  • 4月 ソニーをやめてメルペイに転職
  • 5月 旅行で小豆島、豊島、徳島に行った、豊島よかった
  • 6月 上海行った
  • 10月 Engneering Managerになった
  • 12月 クソ忙しい

というわけで忙しいけど楽しくやってます。

技術的には、GCP, GKE, Terraform, Microservicesという感じで最近はGoよりyaml書いてます。

GAE/Goをdelveでデバッグする

AppEngine/Goでこれまで開発していて、必要な箇所はログを出していれば状態が取れていたのであまりデバッガが使いたくなることがなかったんですが、 最近ちょっとデバッガを使いたい状況があり、AppEngine/Go のローカルサーバに対してDelveをつないでデバッグしたので、やり方を書いておきます。

※基本的に以下はMacでのやり方になります。Linuxもそんなに変わらないと思う。

準備

Delveをインストールします。

go get -u github.com/derekparker/delve/cmd/dlv

GUIを提供する gdlvというのも入れてもいいかもしれません。

サーバを起動

AppEngine/Goのローカルのサーバを立ち上げます。このとき、オプションが必要です。

goapp serve -debug <PATH_TO_YAML_DIR>

または、

dev_appserver.py --go_debugging  <PATH_TO_YAML_DIR>

以前は、delveAppengineなどを使う必要があったみたいですが、今はdebugオプションがあるので不要になりました。

delveをアタッチ

まずアタッチするプロセスのpidを調べます。

$ ps au | grep _go_app

52613 ttys003    0:00.03 /var/folders/wn/xxxxxxxxxxxxxxxxx/T/tmptMHgJNappengine-go-bin/_go_app

アタッチします

dlv attach <pid>

ここは、sudoが必要かもしれません。 また、自分の環境では MacのOS のversionが古いせいか、以下のようにpathを指定する必要がありました。

dlv attach 52613 /var/folders/wn/xxxxxxxxxxxxxxxxx/T/tmptMHgJNappengine-go-bin/_go_app

delveでデバッグする

あとは、delveでブレークポイント貼ってデバッグしていく感じです。 ここでは解説しませんが、 bブレークポイント貼って、cで回して、nでステップ実行して、 sでステップインして、pで見たい変数見て、lで今いるところを確認する、くらい知っておけばとりあえず使えると思います。 delve/Documentation/cli

初めて使いましたが gdbっぽい感じで使えてあまり違和感なかったです。

その他

たぶん設定すればエディタと連携してもっと便利に使えると思います。

以上です。

ドメインをgoogle domainsに移管してみた

きっかけ

放置気味だったDigial OceanからRebootが必要だからバックアップとかしてrebootしろ、という案内が来てた。 Digital Oceanは昔作ったままなのでvagrantでデプロイするような仕組みになってたし、tjun.org のブログの方は放置してたので、もう全部消そうと決意。 tjun.orgは最近使い慣れているGAEに移す方向で、その際DNSとかも直さなきゃということで、なんとなくGoogle Domainsに移すことにした。

移管の流れ

まずはGoogle Domainsの方で、Transfer Inのところで移管したいドメインを入れてみましょう。 未対応のトップレベルドメイン(jpなど)はGoogleDomainsの方で未対応なので移管できません、と言われます。

次に、転出元(自分の場合はさくらインターネット)で取得してたので、まずそちらで転出の準備をします。 ドメイン管理画面のところから、特に問題なく転出の手続きができました。メールが来るまで2-3日かかったと思います。

この際に、Admin のEmailを自分のemailに直してくれるのですが、GoogleDomainsへの移管の承認には Registrant Emailを自分で受け取って承認する必要があります。(ここがさくらのemailアドレスになっていた)  なので、以下の手順で Registrant Emailを変更します。

【JPRS管理】gTLDドメイン 公開情報の変更 – さくらのサポート情報

次に、Google Domainsの方で、Transfer Inのところでドメインを入れて、必要な Auth Codeを入れて、届いた承認メールを確認すれば移管できます。

費用

ちゃんと読んでいなかったけど、 1400円くらいかかりました。 たしか期間を1年延長して移管する、という形になっているので、これは手数料ではなくドメインの更新の費用と思います。ですので、ドメインによって料金は変わります。

特徴など

あまり把握していないですが、以下のような感想です

  • WhoIs情報をprivateにすると、名前も含めて保護されるので、安心感ある
  • ネームサーバは ns-cloud-*.googledomains.com で、これは Googleの Cloud DNSと同じらしい
  • なので、おそらく Cloud DNS相当のパフォーマンスや可用性がある
  • DNSSECなども管理画面で設定すれば利用可能なところも Cloud DNSと同等
  • 管理画面は、普通に使いやすい

簡単ですが以上です。

GoogleAppEngineのManagedSSLを使ってみた

ちょっと前にAppEngineのManagedSSLというのが発表されました。

今までも証明書設定してSSLで使っていたので、最初はどういうことなのかよく分からなかったんですが、使ってみたら便利でした。

やり方は Google Cloud Platform Blog: Introducing managed SSL for Google App Engine に書いてある通りに、AppEngineのSetteingから Enable ManagedSecurity を押すだけです。少し待つと適用されます。 サブドメイン切ってもそれぞれSSLを有効にできます。

見ればわかりますが、Let's Encrypt の証明書です。

ManagedSSLのいいところは、無料で、簡単に設定できて、自動で更新もしてくれるところです。証明書買って、設定して、更新するの、結構面倒です。 とりあえず暗号化したいだけなら、これで十分という感じがしました。

今からgoでwebサーバ書くならchiがいいかも

goでwebサーバを書く時、フレームワーク的なもののデファクトがいまいちない感じですが、chiを触ってみたらよさそうだったので紹介します。

これまでのgoでのWeb開発

去年くらいに調べたときの感じでは、

  • 標準のnet/httpでいいでしょ + routerに gorilla/muxみたいな薄いライブラリを入れる
  • 比較的軽めのframeworkで、 echo, Gin, goji など
  • Railsみたいなのが欲しい人はrevelとか beegoとか?

という感じでした。

個人的には、goで書くならあまり重いフレームワークは使いたくないけど net/httpはしんどそう、ということで今までは echo使ってました。結構よかったです。contextを引き回しておけば、そこから必要なものが取得できていい感じに書けました。

echoよかったけど・・・

echoよかったんですが、今から使おうと思うと自分の場合以下の点が気になりました。

  • contextの取り扱いが echo ver.2 から ver.3で変わっていて、AppEngine+go1.8で使おうと思うといまいちだった
  • echo作ってるチームがarmorというのを後から始めていて、echo今後もやっていくのか少し不安がある

という感じで、AppEngine+Go1.8で使うならあまりオススメできません。

chiよさそう

そこでechoの代わりに使えるものを探してみて、chiを知りました。

go-chi/chi: lightweight, idiomatic and composable router for building Go HTTP services

READMEにある説明によると

  • 軽量
  • 高速
  • 標準pkg以外の外部パッケージに依存しない
  • net/httpに100%準拠
  • APIをモジュール化できる仕組み(ミドルウェア、routeグループ、subrouter)

ということで、薄いpkgでルーティングをいい感じにしたい人にはぴったりです。

chiのレポジトリのREADMEにある以下のコードを見ると、できることがだいたい分かると思います。

import (
  //...
  "context"
  "github.com/go-chi/chi"
  "github.com/go-chi/chi/middleware"
)

func main() {
  r := chi.NewRouter()

  // A good base middleware stack
  r.Use(middleware.RequestID)
  r.Use(middleware.RealIP)
  r.Use(middleware.Logger)
  r.Use(middleware.Recoverer)

  // Set a timeout value on the request context (ctx), that will signal
  // through ctx.Done() that the request has timed out and further
  // processing should be stopped.
  r.Use(middleware.Timeout(60 * time.Second))

  r.Get("/", func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("hi"))
  })

  // RESTy routes for "articles" resource
  r.Route("/articles", func(r chi.Router) {
    r.With(paginate).Get("/", listArticles)                           // GET /articles
    r.With(paginate).Get("/{month}-{day}-{year}", listArticlesByDate) // GET /articles/01-16-2017

    r.Post("/", createArticle)                                        // POST /articles
    r.Get("/search", searchArticles)                                  // GET /articles/search

    // Regexp url parameters:
    r.Get("/{articleSlug:[a-z-]+}", getArticleBySlug)                // GET /articles/home-is-toronto
    
    // Subrouters:
    r.Route("/{articleID}", func(r chi.Router) {
      r.Use(ArticleCtx)
      r.Get("/", getArticle)                                          // GET /articles/123
      r.Put("/", updateArticle)                                       // PUT /articles/123
      r.Delete("/", deleteArticle)                                    // DELETE /articles/123
    })
  })

  // Mount the admin sub-router
  r.Mount("/admin", adminRouter())

  http.ListenAndServe(":3333", r)
}

ルーティングにmiddleware入れる仕組みがあるのがいいですね。

例えば、ベーシック認証を行うmiddlewareは次のように書けます。

var userPasswords = map[string]string{
    "user": "PassW0rd",
}

func basicAuth(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        usr, pw, ok := r.BasicAuth()
        if !ok {
            w.Header().Set("WWW-Authenticate", "Basic")
            w.WriteHeader(http.StatusUnauthorized)
            http.Error(w, "auth required", http.StatusUnauthorized)
            return
        }

        if userPasswords[usr] != pw {
            http.Error(w, "incorrect auth info", http.StatusUnauthorized)
            return
        }

        next.ServeHTTP(w, r)
    })
}

で、ベーシック認証かけたいところで

    r.With(basicAuth).Get("/internal", secretPage) 

という感じで使うことが可能です。

gorilla/muxを使ったことはないけど、READMEを読む限り、書き方的にはchiが好きの方が好きです。

ということで、ドキュメントを読んでちょっと触ってみた限り、とてもいい感じがするのでオススメです。