Rso's Jotter

日々の開発の知見のメモやその他雑記

FireStoreの定期バックアップを実施したメモ

Firebaseを使用している新規Webサービスで、いい加減バックアップを取っておかないとまずいよね、ということがあり、バックアップを取ってみたんですが、その内容のメモになります。

前提

  • FirebaseのBlazeプラン以上でないと実行できません。

手順

以下の2つの公式の説明を見れば終わりなのですが、以下手順と所感です。

firebase.google.com

firebase.google.com

始めてみたとき、あれ、2つの方法があるのかなと思いましたが、よくよく見ると、1つ目の記事はgcloud コマンドラインツールで import / export する方法で、 2つ目の記事は exportを cloud function で定期実行する方法、ということになります。なので定期的なバックアップ取得〜リストアのテストまでやるには、上記の両方の記事を参照する必要があります。

定期的なバックアップ取得(Export)

ここでは詳細は手順を書いても公式と同じになってしまうので、ざっくり概要のみ書くと、

  • cloud functionを作成してデプロイする(Blazeプランじゃないとデプロイ時にエラーになる)
  • GCPから新しいバックアップ保存用のバケットをCloud Storageに作成する。(Firebaseコンソール画面からは見えない)
  • gcloud, gsutil コマンドで エクスポートして保存できる権限を付与する。(gcloud コマンドがインストールされてない場合インストールする。後のリストアでも使用する)
  • GCPのCloud Scheduler から、作成した定期バックアップを手動で起動して、 Cloud Storageに保存されることを確認する。

と行った感じです。普段の開発でFirebaseのみ使用している場合、GCPのツール入れたり管理画面に入ったりで、多少戸惑いがあるかもしれません(私はありました)

そして公式には明示的な記載は見つからなかったのですが、エクスポートされたデータはJSONのようにきれいなデータとして出力されません。なのでバックアップが正常に行われているかどうかは、リストアして確認する必要がありそうです。

リストア(import)

インポートは gcloud コマンドを使用してExportしたバケットとバックアップ時のPrefixを指定すればOKです。

ただ、リストア時には以下のような注意事項がありました。

  • データをインポートすると、データベースの現在のインデックス定義を使用して必要なインデックスが更新されます。エクスポートにインデックスの定義は含まれません。

  • インポートでは、新しいドキュメント ID が割り当てられません。インポートでは、エクスポート時に取得された ID を使用します。ドキュメントをインポートするときに、ドキュメントの ID が予約され、ID の競合が防止されます。同じ ID のドキュメントがすでに存在する場合、インポートを行うと既存のドキュメントが上書きされます。

  • データベース内のドキュメントがインポートの影響を受けない場合、そのドキュメントはインポート後もデータベースに維持されます。

特定のコレクションのみのリストアに関して

特定のコレクション グループのインポートがサポートされるのは、特定のコレクション グループをエクスポートした場合のみです。すべてのドキュメントのエクスポートから特定のコレクションをインポートすることはできません。

要するに、フルバックアップで取った場合は、全戻ししかできないようです。 また単純にドキュメントのIDで上書きなので、完全にバックアップ時の状態にそのまま戻るわけでは無さそうで、そうするには事前にコレクションの削除などが必要そうでした。

所感

FirebaseはかんたんなWebサービスならこれ一つでいい感じに開発が進められるのですが、FireStoreがMySQLなどのよくあるRDBとクセが違うのである程度慣れが必要なのですが、さらに運用面でも馴染んでおく必用がありそうです。小さなサービスならとりあえずRDBのダンプ取っておけばなんとかなりましたが、バックアップやリストアの検証してたら初回は時間がかかってしまいました。

こういった運用の準備や検証とかもいれると、いくらFirebaseがさくっと作れると言っても、初回は慣れている技術スタックのほうがやはり早いです。

一度設定して理解してしまえばそんなに難しいことはなく、次回同じことをやる際にはすんなり行けるとは思うので、本当にサクッと作りたいときにサクッと作るには、日頃からこういった細かいテストや検証を経て慣れ親しんでおく必要がありそうです。

Kubernetes for Macから ECRのイメージを取得する方法

Kubernetes for Mac (正確にはDocker for Mac上で動いているKubernetes) でテストするときには、ローカルでDockerイメージ作ってそれを使用することが多いのですが、 ローカルのkubeから直接ECRに登録されている Private Dockerイメージを読みたいことがあったので調べました。 ググったらすぐ出てくる方法なんですが、一応メモっておきます。

手順

前提として、 awscliやcredentialの設定はできてるとします。

ログインできるかの確認

$ $(aws ecr get-login --region ${AWS_REGION} --no-include-email)

まずはdocker loginが動くか確かめます。 AWS_REGISONは適宜指定します。東京の場合は ap-northeast-1 ですね。

次に docker-registryのsecretを作成します。

$ ecr_login="$(aws ecr get-login --no-include-email --region $AWS_REGION)"

$ kubectl create secret docker-registry ecr \
  --docker-username=`echo $ecr_login | awk '{print $4}'` \
  --docker-password=`echo $ecr_login | awk '{print $6}'` \
  --docker-server=`echo $ecr_login | awk '{print $7}'`

次にPrivate Registryのイメージを読み込むyamlに、以下のように imagePullSecrets を指定してやります。

gist.github.com

あとはこのyamlファイルを applyすればOKです.

参考

kubernetes.io

blog.omerh.me

Docker/Kubernetes 実践コンテナ開発入門

Docker/Kubernetes 実践コンテナ開発入門

Nuxt.js(SPA), Firebase Hosting, Cloud Function でOGP対応してみた

以前、内輪の開発合宿で Quizhub というサービスを作ってみたんですが、 OGP対応したいよねという話が出てきました。

このサイトはFirebase Hostingを使用しているので、Nuxt.js の SSRは使用できません。 対策をググったらいろいろ出てきたので、まあできるだろうと思ったら、思ったより手こずってしまったのでその内容をメモしておきます。

OGPとは?

あまり詳しく書きませんが「Open Graph Protocol」の略で、これに沿った形式でmetaタグを書いてやると、 それに対応しているサービスでURLを貼ると、そのタイトルや概要、画像などがきれいに表示され、見やすくなります。 Twitter, LINE, SlackなどでURLを貼るとぺろっとその内容がでてくるアレです。

SPAの問題点

SPAはビルドした時点でファイルが生成されるので、QuizHubでいうとクイズ詳細画面で、クイズタイトルや概要、使用されている画像をmeta tagにいれることができません。

対応内容

内容はここのブログの方法を参考にさせていただきました。というか、ここの内容の2番煎じです。

www.memory-lovers.blog

クイズ詳細画面を Vue-routerからは /quizzes/show?id=xxxx/quizzes/:quiz-id の 2通りでアクセスできるようにしてやります。 /quizzes/:quiz-id のURLはSPAでは対応する静的ファイルは生成されないので、リロードするとページが見つからない状態になります。 この部分をcloud functionで拾ってやります。具体的には以下のような記述をします。

 "rewrites": [
      {
        "source": "/quizzes/*",
        "function": "quiz"
      }
  ]

これで クローラなどの /quizzes/:quiz-id への直アクセスはCloud Functionが起動し、 ここでmetaタグをよろしく出力し、 /quizzes/show?id=xxx ヘリダイレクトするという方法を取りました。

ハマったポイント

最初は /show?id=xxxx のページをCloud Functionで動かそうと思っていたのですが、 Firebase Hostingは 優先順位が以下のように決まっているので、既に静的コンテンツが存在する場合は、Cloud Functionは実行されずに、静的コンテンツがそのまま返ります。 そして SPAでgenerateした際は実際は /show/index.html が生成されているのですが、ここで静的コンテンツの名前が完全一致していることにきづけず、Cloud Functionを設定しているのに動かない!! となって時間を食ってしましました。

firebase.google.com

/__/* パスセグメントで始まる予約済みの名前空間

リダイレクトの構成

正確に一致する静的コンテンツ

リライトの構成

カスタムの 404 ページ

デフォルトの 404 ページ

また、Firebase HostingからCloud Functionの起動が、Cloud Functionがus-central1 リージョンじゃないと駄目らしく、 東京リージョンでデプロイしたCloud Functionが動かない!!みたいになりました。

課題

一応やっつけで動いたのですが、以下の課題があります。

  • リダイレクトされたURLをそのまま共有すると、そのURLはOGPがでない。
  • Cloud Functionがそこそこ遅い。(キャッシュなどで対策すると良い?)

ただ、はてなのリンクでも以下のようにイイ感じで表示されるようになりました。 quizhub.info

他の方法

以下の記事ではCloud FunctionでNuxtを動かして、そこでSSRをやるという方法を取っています。こうすれば、上記のリダイレクトによってURLが変わってしまう課題は解消しそうです。

medium.com

また、今回は試していませんが、Netlify には Prerendering という機能があるそうなので、OGP対応に閉じるぐらいの要件なら、こちらに移るという手もありかなと思います。

所感

サクっとできそうだったので、思ったより手間取ってしまったので、残しておきました。 あまりスマートなやり方ではないと思いますが、根本的に解消するには、Firebase Hostingで頑張らずに、Nuxt.js などのSSRの仕組みを使用できる環境に移すべきだと思いました。

受託開発が面白くないから自社サービスという転職動機について

最近、すごく久しぶりにエンジニアの面接を行いました。 応募者は若手のフロントエンド志望のエンジニアでした。

まずはじめに、よくあるなぜ今転職活動をしているのか伺ったところ、自社の受託請負のシステム開発が面白くなくて、自社サービスで開発しているところを探している、という答えが返って来ました。

この動機、よく聞く気がしていて、そういえば自分がSI企業に所属していたときに転職活動をしていたときにも発言していた記憶があります。

なぜ受託は面白くなくて自社サービスのほうが面白いと思うのか?

という質問を投げかけてみると、ざっくりその答えは、

  • 納期に間に合わせるために低品質で妥協した開発を行っている
  • ユーザ(顧客)のいいなりになって、達成感がない。エンドユーザが見えない。
  • 複数の案件を抱えている人が多数で、細切れの作業になってしまっている。

というような感じでした。なるほどありがちな問題ですね。

しかし、スタートアップで自社サービス開発を約3年経験した身から言うと、上記の問題は自社サービスだから解消される、というものではないと思います。自社サービスであっても、

  • 顧客への提案やユーザからのフィードバックの対応の納期が非常に短いことは有りえて、そのために納期最優先の開発を行うことは普通にある。とくに立ち上げ初期の場合は、有力な顧客からの要望にいち早く答えたいため、ビジネスチームから現状のスケジュール無視で最速で出して欲しい、という要望に対応することもある。
  • 受託だと最終的にユーザの決定に従うという選択があるが、自社サービスだと方向性に悩んだ場合、何をすべきか迷う場面がある。その場合、ピボットの頻度が増え、自分の苦労して開発したプロダクトがお蔵入りになることもよくある。その場合はもちろん達成感は得られない。
  • エンドユーザが見えるかどうかについては、受託か自社サービスと言うより、プロダクトの規模によると思われる。プロダクトの規模が小さいほど、開発者ロールでもユーザからのフィードバックが見える。
  • 複数の案件を抱えなければいけない問題に関しては、そのプロジェクトがどのくらい健全な予算と人員をもっているかによる。儲からないプロジェクトに専任のエンジニアを割り当てるのは難しいし、また予算はあっても人員がいない場合は専任では張り付けない。

という問題があって、それほど受託と変わらない問題に直面すると思われます。

(このあたりも、もちろん環境によって異なるし、やってみるまで分からないところではありますが..)

結局のところ、組織とプロダクトのフェーズによって変わる

上記のような面接を経て思ったのは、結局のところもともと上記の請負で面白くないと思っていた要因は、受託か自社サービスということではなく、以下の2つではないかな、ということです。

  • 組織とのプロダクトのフェーズ
  • そのプロジェクトの予算と人員の健全かどうか

プロダクトや組織の規模が小さいほど、全体を見渡すことができ、ユーザからのフィードバックが得られ、自らの開発物がユーザに便益を与えていることを実感することがしやすいです。 組織が小さいほど、全体を見渡せるスキルセットの方が歓迎されがちで、その分特定の分野のスペシャリストは活躍しづらくなる傾向があります。

また納期や複数案件細切れの問題は、そのプロジェクトに潤沢な予算があり、余裕を持ったスケジュールと人員をアサインされているかどうかによって、変わってくるのではないかなと思いました。

まとめ

あまりまとまりのない話ですが、巷で言われている受託が嫌だ的な動機は、結局のところ その組織が大きすぎて自分の活躍が実感できない のと、 そのプロジェクトが健全でない 、ということだけなのではないでしょうか。

読書メモ 認証サバイバルガイド

ひっそりと書いているブログですが、意外に、xxxについて書いてたよねとか言ってもらえて、ひっそりと喜んでます。

せっかくなので読者になるボタンを表示してみました。はてなユーザの方は押してもらえると励みになりますのでお願いできればと思います。

さて今回は、Auth0が公開している認証サバイバルガイドを読みました。

auth0.com

概要

以下そのまま引用です。

本書は、認証に関わりはじめた方々に、初めの一歩としてお読みいただくことを目的としてつくられています。 認証を実装する際に出会うであろう全ての主要のプロトコル、フォーマット、コンセプトそして定義について、一通り説明しています。

まさになんとなく雰囲気で認証(Auth0)を触っている自分にふさわしいですね。 メールアドレスを登録すればPDFをダウンロードできます。

内容抜粋

以下自分の理解をざっくりかいたものです。間違っているかもしれません。

OAuth2.0

  • もともと認可のためのプロトコル。これによりアプリケーションがユーザのクレデンシャルを知らなくてもユーザのもつ外部リソースにアクセスできる許可が得られる。
  • 認証を目的にしているわけではないが、運用上認証の用途でも使われだした。
  • 細かい規定がないので、認証に関しては実装者の解釈によってあいまいになる部分が多かった。

Open ID Connect

  • 上述の問題をうけて OAuth 2.0 を拡張。 認証に関する内容も規定している。
  • OAuth 2.0 での曖昧な領域を形式化している。たとえば、トークンのフォーマットはIDトークンであればJWTにしないといけない、など。

SAML と WS-Federation

  • MS の Active Directory のような、クローズドネットワークでしか動かせないSSOを何とかすべく、登場した。
  • SAMLはXMLでやり取りし、SOAP全盛だった頃に合わせて流行っていたが今は HTTP, JSONベースの方が簡単で主流。
  • WS-* といろんなシリーズのプロトコルがあったが、 WS-Federationが一番まとも。

アクセストークン

  • OAuth2, OpenID Connect では、 以下のトークンのタイプがある。

    • アクセストークン
    • リフレシュトークン
    • IDトークン
  • 初めて学んだ人はなんでアクセストークンとリフレッシュトークンは別れているの?と思われる。主にセキュリティ上の理由だが以下の通り。

    • アクセストークンはリソースサーバに対して投げるが、リフレッシュトークンは認可サーバに対して投げる。
    • アクセストークンの有効期限は短くしたい。
    • リフレッシュトークンは寿命の長いクレデンシャルという意味では、パスワードに近い性質をもつ。なので保存方法もケアが必要。

トークンの保存

  • トークンの保存方法はいろいろあってそれぞれメリデメがある。
  • 一番スタンダードなのは ブラウザならLocalStorageだよね。

トラブルシューティング

  • トラブルシュートするにはHTTPの仕組み分かってると捗るよ。
  • HARファイルに保存したら再生できる。HARファイルにはパスワードも残るからユーザから取るときは気をつけて。

所感

おそらく本当に第一歩というはじめの部分だけなんだと思いますが、まとまっていてわかりやすいと感じました。

Auth0やFirebase Auth, AWS Cognito など 認証サービスがどんどんコモディティ化してくるような流れを感じる一方、 その裏の仕組みはいろいろ新しいものが登場してくるので、より初学者がキャッチアップが辛くなってくるんじゃないのかなと思っています。

そういうときに、こういう今までの流れと、いまどうなっているかを概説してくれる資料はありがたいです。