tag:crieit.net,2005:https://crieit.net/tags/GCP/feed 「GCP」の記事 - Crieit Crieitでタグ「GCP」に投稿された最近の記事 2021-11-17T09:36:55+09:00 https://crieit.net/tags/GCP/feed tag:crieit.net,2005:PublicArticle/17765 2021-11-17T09:36:55+09:00 2021-11-17T09:36:55+09:00 https://crieit.net/posts/102949946b0e6197f103d453a781a1fc 数日で有料サービスをリリースしてみた話 <p>有料サービスを2,3日位で作ってリリースしてみました。多分計10時間ほど? 急にぱっと思いついて次の日の夜くらいにはだいたい完成していました。作ったのは下記のHand Refactorerというプログラムのコードを手動的にリファクタリングしてくれるサービスです。</p> <blockquote class="twitter-tweet"><p lang="ja" dir="ltr">130円でプログラムのコードを手動的にリファクタリングしてくれるサービスをリリースしました。プログラミングを始めたばかりの方にはもしかしたら役立つ場合もあるかもです。よろしければお試しください!!<a target="_blank" rel="nofollow noopener" href="https://t.co/bHlNXJFbTh">https://t.co/bHlNXJFbTh</a> <a target="_blank" rel="nofollow noopener" href="https://t.co/VhPI80a6Cl">pic.twitter.com/VhPI80a6Cl</a></p>— だら@Flutterもやってる (@dala00) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/dala00/status/1459816338050859008?ref_src=twsrc%5Etfw">November 14, 2021</a></blockquote> <p>ちなみにこれ自体は単に自動的じゃなくて手動かよというツッコミがほしいだけのために作ったネタクソアプリです。</p> <p>色々やるべきことを削ったりなどで考えたりしたので書いておきます。</p> <h2 id="サービスの流れ"><a href="#%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%AE%E6%B5%81%E3%82%8C">サービスの流れ</a></h2> <p>そもそもサービスの流れですが、まずユーザーがリファクタリングしてほしいコードを入力して登録します。</p> <p>それを僕が人力でリファクタリングし、回答として登録するとユーザーがそれを確認できる、という形です。</p> <h2 id="課金関連の開発を極限まで削る"><a href="#%E8%AA%B2%E9%87%91%E9%96%A2%E9%80%A3%E3%81%AE%E9%96%8B%E7%99%BA%E3%82%92%E6%A5%B5%E9%99%90%E3%81%BE%E3%81%A7%E5%89%8A%E3%82%8B">課金関連の開発を極限まで削る</a></h2> <p>課金となると、結構色々考えなければなりません。ユーザー登録し、そのユーザーに対して課金ログを保存し、購入履歴などを用意する必要があります。ただそこまでするとどうしても工数がかかってしまいます。そのため下記のようにして開発事項を削りました。</p> <h3 id="オーソリを使う"><a href="#%E3%82%AA%E3%83%BC%E3%82%BD%E3%83%AA%E3%82%92%E4%BD%BF%E3%81%86">オーソリを使う</a></h3> <p>オーソリというのは、仮売上です。即課金確定するのではなく、注文が確定した時にキャプチャという処理を行って決済を確定させる方法です。ユーザーが注文してきた時に仮売上とし、僕が処理を行って納品でき、ユーザーがそれを意図的に閲覧した場合に納品確定としキャプチャを行うようにしました。</p> <p>この方法には色々メリットがありました。</p> <h4 id="ユーザーの心理的不安を取り除ける"><a href="#%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%AE%E5%BF%83%E7%90%86%E7%9A%84%E4%B8%8D%E5%AE%89%E3%82%92%E5%8F%96%E3%82%8A%E9%99%A4%E3%81%91%E3%82%8B">ユーザーの心理的不安を取り除ける</a></h4> <p>個人サービスですので、そこに課金するのにはちょっと不安があります。ただ、ちゃんと納品が行われないと課金が確定しないということが事前にわかっていればその不安をある程度取り除くことができます。</p> <p>確定する場合には、ユーザーに回答画面のURLが貼られたメールが送られます。ここでも実際に見て課金を確定するかどうかをユーザーが意図的に選ぶ事ができます。興味がなければ見ずに終わらせればいいですし、お金を払ってでも見たいと思っていれば閲覧して確定できます。</p> <h4 id="運営側の不安も取り除ける"><a href="#%E9%81%8B%E5%96%B6%E5%81%B4%E3%81%AE%E4%B8%8D%E5%AE%89%E3%82%82%E5%8F%96%E3%82%8A%E9%99%A4%E3%81%91%E3%82%8B">運営側の不安も取り除ける</a></h4> <p>個人サービスで課金機能を提供するのは、運営者としてもなかなか気持ち的に不安になることが多いです。うまくサービスを提供できなかったらどうしよう、大きなミスに気づかず迷惑をかけてしまったらどうしよう、など。</p> <p>しかしオーソリを利用してユーザーがお金を払って結果を見たいと確信して行動する時に初めて課金が行われるようにすれば、なかなか間違えたり問題が起こる可能性は低くなります。そうなると運営側としても問題が発生しにくく安心です。</p> <p>また、最悪僕が怠けたりなにか急なトラブルで全然手を付けられず放置したとしても一切課金されることはありません。また、そんなにリファクタリングすることがないコードであれば確定しないことでキャンセル扱いにすることもできます。</p> <p>このようにしてお互いの不安をなるべく少なくすることでユーザーは購入を、運営はリリースをしやすい気持ちにできるようにしました。これができなければ色々と複雑なテストをしたり入念にいろいろな機能をつくったりしてなかなかリリースはできなかったでしょう。</p> <h3 id="チェックアウトを使わない"><a href="#%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E3%82%A2%E3%82%A6%E3%83%88%E3%82%92%E4%BD%BF%E3%82%8F%E3%81%AA%E3%81%84">チェックアウトを使わない</a></h3> <p>Stripeにはチェックアウトというプログラムを書かなくても商品を売れる機能があります。すごく簡単なのですが今回はそれは使いませんでした。というのも売上の結果を知るためにWebhookでチェックする必要があり、ちょっとそれが面倒でした。プログラムで決済してしまえば登録時に一緒にやってしまえばすべてが終わるためそちらの方が処理的にもわかりやすくテストもしやすかったためです。</p> <h2 id="メールアドレスを使う"><a href="#%E3%83%A1%E3%83%BC%E3%83%AB%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%82%92%E4%BD%BF%E3%81%86">メールアドレスを使う</a></h2> <p>メールアドレスを使うことでログイン機能を削りました。ユーザー登録をすると、やはり離脱率は上がります。ちょっと投稿して利用するだけのサービスでユーザー登録は面倒くさいです。</p> <p>また、ログイン機能を作るとそれはそれで結構面倒です。Next.js と Firebase を使っているのですが、それで認証を入れるとFirestoreのセキュリティルールも設定しなければなりませんし、その状態だとNext.jsのサーバーサイドレンダリング時にエラーが発生することもあり、結構確認事項が増えます。ログイン機能を作らずメールアドレスのみの照合とすることでそれら全ての開発を削りました。</p> <p>メールアドレスだけでは勝手に決済されて危険なのでは? と思われるかもですが、クレジットカード自体は操作している人自身のものを入れなければならないためなりすましは難しいですし、できたとしても結局オーソリまでしか進めないため、利用者が最後まで進まないとお金は一切動きません。</p> <p>またこれにより結果のURLはメールで本人しか知ることができないため漏洩の心配などもありません。</p> <p>最初はユーザーもメールアドレス登録するのはいやかな…とも思ったのですが、そもそも大量の依頼がくるとそれはそれで僕のスケジュールがパンクしてしまうのである意味抑制になっていいかなと思っています。</p> <h2 id="極限までハードルを下げる"><a href="#%E6%A5%B5%E9%99%90%E3%81%BE%E3%81%A7%E3%83%8F%E3%83%BC%E3%83%89%E3%83%AB%E3%82%92%E4%B8%8B%E3%81%92%E3%82%8B">極限までハードルを下げる</a></h2> <p>このハードルというのはユーザー、運営者両方のことです。</p> <p>まず費用は130円という自販機でジュースを買うのと同じ(?)ような料金にしました。また、説明分にはレジャー感覚で使ってほしいということ、意図した結果が帰ってくるとは限らないということを書いておき、運営者的にもちゃんとした結果をださなければ、という不安をなくし、利用者としてもさほど結果に期待しない状態を作っておきました。</p> <p>ハイクオリティになったり、ハードルの認識の齟齬があると開発もそれに対処するためにちょっとやることや考えることが増えたりなど、すぐにリリースはできません。とにかくすぐに作るレベルのサービスに連動したクオリティの商品をそれに見合った低価格で提供することによってリリース時の負担を下げました。</p> <h2 id="管理機能を公開しない"><a href="#%E7%AE%A1%E7%90%86%E6%A9%9F%E8%83%BD%E3%82%92%E5%85%AC%E9%96%8B%E3%81%97%E3%81%AA%E3%81%84">管理機能を公開しない</a></h2> <p>リファクタリング結果の送信ですが、Firestoreのダッシュボードだけではできません。そのためそこは返答用の画面を作ってあげる必要がありました。</p> <p>しかし前述の通り認証もありませんし、URLを作ってしまうと万が一アクセスされてしまった時に情報が漏洩してしまいます。</p> <p>そのため管理画面は公開せず、別プロジェクトとして作り、ローカルのデバッグ実行だけでできるようにしました。絶対に他の人にアクセスされることもありませんので安全です。また、作っていたプログラムをコピーするところから始めたのでベース部分はまるまる流用でき、特に大変でもありませんでした。</p> <h2 id="Firebaseクライアントを使わず全部APIのみにする"><a href="#Firebase%E3%82%AF%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%B3%E3%83%88%E3%82%92%E4%BD%BF%E3%82%8F%E3%81%9A%E5%85%A8%E9%83%A8API%E3%81%AE%E3%81%BF%E3%81%AB%E3%81%99%E3%82%8B">Firebaseクライアントを使わず全部APIのみにする</a></h2> <p>前述の通り、セキュリティルールを設定するのが面倒だったためFirebaseのクライアントはアクセス解析にしか使っていません。セキュリティルールは全部のデータへのアクセス不許可にしています。</p> <p>普通に単なるAPIとしてfirebase-adminを利用してサーバーサイドのDBのようにして作っています。なにもかんがえることもなく非常に楽です。勝手に変なデータにアクセスされてしまうこともありません。</p> <p>また、Firestoreを使うことによってデプロイする場所を選ばなくてもよいようにもなっています。</p> <h2 id="Cloud Runにデプロイ"><a href="#Cloud+Run%E3%81%AB%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4">Cloud Runにデプロイ</a></h2> <p>今回はCloud Runにデプロイしました。前述の通りDBはFirestoreなのでどこにでもデプロイできます。本来はVercelが一番楽なのですが、この無料プランは個人的な利用のみに限られますので、今回の場合は利用できません。ということでCloud Runを使いました。GitHubにpushしたのに連動して自動的にデプロイもできますし。Herokuでも良いと思いますが頻繁に利用されるサービスではありませんし、あまりアクセスして遅いのもあれかなと思いCloud Runにしました。</p> <p>せっかくなのでDockerfileを使わないでデプロイできるBuildpackというものを試してみたかったというのがあったのですが、どうもビルド無しで実行されてしまうようでエラーになったので今回は諦めてDockerfileを使うことにしました。だいたいDockerfileならどっかーにあると思いますので。</p> <p>今回は下記を使いました。<br /> <a target="_blank" rel="nofollow noopener" href="https://zenn.dev/kazumax4395/articles/427cc791f6145b">【Node.js/Next.js】Cloud Runで動作する軽量なDockerを構築してみた</a></p> <p>これの真ん中のやつでだいたいデプロイに8分ほどかかります。それほどパフォーマンスが必要ではないので一番最初の簡易的なやつでも良かったのかもしれません。なんにしろVercelよりはやはりどうしても遅くなってしまいますね。</p> <p>あと日本リージョンにしたのでちょっとネットワーク料金がかかります(アクセスがちょっと多ければ月何十円とか100円とか?)</p> <h2 id="CSSも使わない"><a href="#CSS%E3%82%82%E4%BD%BF%E3%82%8F%E3%81%AA%E3%81%84">CSSも使わない</a></h2> <p>今回はChakra UIを使いました。とにかくデフォルトのデザインパーツで、カスタマイズは全部Chakraコンポーネントのプロパティのみで、ぶわっと作りました。非常に楽です。</p> <h2 id="DIFFの表示"><a href="#DIFF%E3%81%AE%E8%A1%A8%E7%A4%BA">DIFFの表示</a></h2> <p>リファクタリングということで、DIFFを表示したほうがわかりやすいかなと思いました。</p> <p>React Diff Viewerというのを使いました。<br /> <a target="_blank" rel="nofollow noopener" href="https://github.com/praneshr/react-diff-viewer">https://github.com/praneshr/react-diff-viewer</a></p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>最初に書いたとおりクソアプリですので、ものすごい依頼が増えない限りは特にアップデートする予定はありません(依頼がきたらちゃんと対応します。リファクタリングは結構好きなのでわりと楽しんでやっています)。</p> <p>ただ数日で作れたので、これを機に低価格で同じように自分で提供できることを売るのも面白いかなとは思います。どうしても手がかかるので規模が大きくなるとスケールもしないし限界がありますので、あくまでも今回のようにジョーク交じりかつすごく負担の少ない作業だけになるとは思いますが。</p> <p>逆に言うと、低価格でちょっとなにか提供できる、というひとはたくさんいると思いますので、みんながこういうサービスを各々作れたら面白いのにな、とも作ってる途中に思いました。例えば小説の手直し、絵の手直し、もしくはちょっとした絵を書いてあげたり、サービスの感想を伝えてあげたり、なにか写真をとってあげたり、ロゴをつくってあげたり。皆自分の得意なことを提供して少しでもお金になれば楽しいのでは、と思いました。</p> <p>もちろんそういうモール的なサービスはいくつかあると思いますが、あくまでも自分の個人商店的な感じで運用するのも面白いと思います。</p> <p>自分でみんながそういうことを提供できるサービスを作ればよいのでは、とも一瞬思ったのですが、やはり価格的に運営者に入るお金はかなり薄利になり、儲けを出すにはかなり大量に集客しないといけませんし個人だと逆に大変なことが多そうなので、無理かなと思いました。Skebのもっと安くて気軽バージョン的な感じかもです。</p> <p>なので可能な方は是非同じ様なサービスを作ってなにか提供してみると面白いのではないかと思います。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/16345 2020-12-12T10:06:10+09:00 2020-12-12T10:06:10+09:00 https://crieit.net/posts/GCP-GCE-VNC-OBS-openSUSE ☆GCPのGCEでVNCのOBSしたやつは、やつの名は、openSUSE…!! <h1 id="☆GCPのGCEでVNCのOBSしたやつは、やつの名は、openSUSE…!!"><a href="#%E2%98%86GCP%E3%81%AEGCE%E3%81%A7VNC%E3%81%AEOBS%E3%81%97%E3%81%9F%E3%82%84%E3%81%A4%E3%81%AF%E3%80%81%E3%82%84%E3%81%A4%E3%81%AE%E5%90%8D%E3%81%AF%E3%80%81openSUSE%E2%80%A6%21%21">☆GCPのGCEでVNCのOBSしたやつは、やつの名は、openSUSE…!!</a></h1> <h2 id="はじめに"><a href="#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB">はじめに</a></h2> <p>この記事は<a target="_blank" rel="nofollow noopener" href="https://adventar.org/calendars/5500">openSUSE Advent Calendar 2020 - Adventar</a>の12日目の投稿です。</p> <p>このたび<a target="_blank" rel="nofollow noopener" href="https://hansendo.com/blog/mrexcluded/opensuseadventcalendar20181201_4196">2年ぶり</a>に参加をキメてみました。普段はDesktopでTumbleweedを使ってソフトウェアを書いたり書かなかったりしていますが、今回は<a target="_blank" rel="nofollow noopener" href="https://cloud.google.com">GCP:Google Cloud Platrofm</a>に関するお話をしたいとおもいます。</p> <p>このお話は、先月11月28日にオンライン開催されたOSC福岡の<a target="_blank" rel="nofollow noopener" href="https://youtu.be/VrtsaycC_I0?t=465">ライトニングトークセション</a>で発表された資料から、クラウドコンピューティングに関する部分を詳解したものです。</p> <p><img src="https://64.media.tumblr.com/749506a2a4b49a60f0a20547ac73218c/e962fe3b57d0d1ac-6a/s640x960/6777b6949a08895c970adefd41b25b1bc756059b.png" alt="image" /></p> <h2 id="なんなのか?"><a href="#%E3%81%AA%E3%82%93%E3%81%AA%E3%81%AE%E3%81%8B%EF%BC%9F">なんなのか?</a></h2> <p>かいつまんで概要を解説しますと、昨今流行りのブロードキャスト映像配信システムをクラウドコンピューティングで実現してみたやつです。図で表すとこのような感じですね。</p> <p><img src="https://64.media.tumblr.com/768d690b79e79bdb202896d2f1b57981/e962fe3b57d0d1ac-27/s1280x1920/1c242cb16f2b382a75e5b8d7284164dec9b7376d.png" alt="図" /></p> <p>GCPが提供するクラウドコンピューティング、それはGCE:Google Compute Engineでワタシは4歳でした。<br /> その味は甘くてクリーミィで、こんな素晴らしいCompute Engineを使えるワタシはきっと特別な存在なのだと感じました。</p> <p>今ではワタシがオジイサン、インスタンスにあげるのはもちろんopenSUSE。<br /> なぜなら、彼もまた特別な存在だからです。</p> <h2 id="なぜなのか?"><a href="#%E3%81%AA%E3%81%9C%E3%81%AA%E3%81%AE%E3%81%8B%EF%BC%9F">なぜなのか?</a></h2> <p>補足しますと、Google Compute Engineというのは、クラウド上に仮想のコンピュータを作成して、インターネット経由で操作することが出来る仕組みを提供してくれるサービスです。たぶん。<br /> で、作成された仮想のコンピュータのことをVMインスタンスみたいに呼びます。</p> <p><img src="https://64.media.tumblr.com/9c17f06b5ad61e5e096b8b18529448da/e962fe3b57d0d1ac-a4/s1280x1920/c9060ec4c6177d41141f00c9aa58b1cb661cad90.png" alt="インスタンスの作成画面" /></p> <p>※画像はイメージです。</p> <p>インスタンスは仮想のコンピュータですので、OSが必要になりますよね。インスタンスにあげるのはもちろんopenSUSE。<br /> なぜなら、彼もまた特別な存在だからです。</p> <h2 id="あるんかいないんかい"><a href="#%E3%81%82%E3%82%8B%E3%82%93%E3%81%8B%E3%81%84%E3%81%AA%E3%81%84%E3%82%93%E3%81%8B%E3%81%84">あるんかいないんかい</a></h2> <p>ということで、AMD Epyc CPUの搭載されたファンタスティックなインスタンスを作成しました。OSはもちろんopenSUSE、ブートディスクから接続されているイメージを変更してopenSUSEを選択しましょう。</p> <p><img src="https://64.media.tumblr.com/6118f2446abe127324ab86be71832816/e962fe3b57d0d1ac-1f/s1280x1920/7c602ff874c50d41c9765593d754704c15b34659.png" alt="ブートディスク選択画面" /></p> <p>そんな、ばかな……</p> <h3 id="ないんかい"><a href="#%E3%81%AA%E3%81%84%E3%82%93%E3%81%8B%E3%81%84">ないんかい</a></h3> <p>最近ちょっと目が悪くなってきたのかもしれないのですが、見つからないです…。<br /> 昔はあったような気がするんですけど、選択できるOSが見つかりません。これではインスタンスを作成することが出来ないッ! 一体どうすれば……</p> <p>※注:この記事はopenSUSEアドベントカレンダーなので、openSUSEが見つからなければこの章で打ち切り未完丸投げ終了なんですが、皆様はぜひ親しみやすいOSを選択してご活用いただければ幸いです。</p> <h3 id="あるんかい"><a href="#%E3%81%82%E3%82%8B%E3%82%93%E3%81%8B%E3%81%84">あるんかい</a></h3> <p>黒い画面「 ^ ^ ありまっせ」</p> <p><a target="_blank" rel="nofollow noopener" href="https://cloud.google.com/compute/docs/images#community_supported_images">コミュニティでサポートされるイメージ | Compute Engine ドキュメント | Google Cloud</a></p> <p>ありました。</p> <p>そう、よりオープンソースソフトウェア色の強いコミュニティサポートイメージとしてなぁッ!!</p> <p><img src="https://64.media.tumblr.com/6a897fec8fa94d5e659eaec9da92d158/e962fe3b57d0d1ac-c9/s640x960/37ac69bd6b58e8ba0e89272e2628ac1789be4e0d.png" alt="使用可能なコミュニティサポートイメージ" /></p> <h3 id="これをこうしてこうじゃ!"><a href="#%E3%81%93%E3%82%8C%E3%82%92%E3%81%93%E3%81%86%E3%81%97%E3%81%A6%E3%81%93%E3%81%86%E3%81%98%E3%82%83%EF%BC%81">これをこうしてこうじゃ!</a></h3> <p>GCPは、ブラウザのコンソールからクラウドシェルっていう機能で黒い画面にgcloudというコマンドを入力することでも操作が出来ます。</p> <p>なので、これをこうして、こうじゃぁあああ!!</p> <pre><code>gcloud compute disks create 作成するディスクの名前 --image-project=opensuse-cloud --image=opensuse-leap-15-2-v20200702 --type=pd-ssd --zone=ディスクを作成するゾーン --size=40GB </code></pre> <p><img src="https://64.media.tumblr.com/2f60f29cc780f5ce6eb00d4c97fd21b8/e962fe3b57d0d1ac-88/s640x960/3e00a34784efb3589341c3064599e491849eb3cb.png" alt="実行に成功した様子" /></p> <p>うまくいきおったら、冒頭のブートディスクに接続されているイメージを変更して、既存のディスクから作成したopenSUSEを選択できるようになっていますわい。</p> <p><img src="https://64.media.tumblr.com/1c5f74921255357955377f064677794f/e962fe3b57d0d1ac-f1/s540x810/47c077056a2d3d616ffc56057415bfa284e599af.png" alt="作成したディスクを選択している様子" /></p> <h2 id="やったぜ!!"><a href="#%E3%82%84%E3%81%A3%E3%81%9F%E3%81%9C%EF%BC%81%EF%BC%81">やったぜ!!</a></h2> <p>では早速起動してみましょう。</p> <p><img src="https://64.media.tumblr.com/dd4ae1cec40f4e57a1da99a239ffdde3/e962fe3b57d0d1ac-81/s500x750/090550fa6f5b550f85da95cc39f7d46c7c04a606.png" alt="起動直後の画面" /></p> <p>やったぜ!! これでyastし放題の心置きなくzypperできる、とびっきりのわがままインスタンスの完成ですね。</p> <p><img src="https://64.media.tumblr.com/0190ef64b389e7b33533022ca82782b0/e962fe3b57d0d1ac-f2/s1280x1920/b6a57bc76f24547ecfb4ef3fbd42a7f940759027.png" alt="YaST2の起動画面" /></p> <p>ゴエー! ブラウザで開くとフォントゴエー!!</p> <h3 id="ここから先は君たちの目で確かめてくれッ"><a href="#%E3%81%93%E3%81%93%E3%81%8B%E3%82%89%E5%85%88%E3%81%AF%E5%90%9B%E3%81%9F%E3%81%A1%E3%81%AE%E7%9B%AE%E3%81%A7%E7%A2%BA%E3%81%8B%E3%82%81%E3%81%A6%E3%81%8F%E3%82%8C%E3%83%83">ここから先は君たちの目で確かめてくれッ</a></h3> <p>ということで、ここから先はopenSUSEの話になりますので、GCPのGCEにあるopenSUSEを使って、自由自在にopenSUSEしてください。ありがとうございました。</p> <p>― 完 ―</p> <h2 id="おまけコーナー"><a href="#%E3%81%8A%E3%81%BE%E3%81%91%E3%82%B3%E3%83%BC%E3%83%8A%E3%83%BC">おまけコーナー</a></h2> <p>上記のopenSUSEを、とびっきりのわがままopenSUSEして動画配信をしたときの様子は下記のとおりです。</p> <p><img src="https://64.media.tumblr.com/bf69453a9f01534787b8447db2799d45/e962fe3b57d0d1ac-8e/s1280x1920/e55c2e414b7445e748e9b4d43d92a42f65bf53d0.png" alt="動画配信時のイメージ" /></p> <p>こんな感じで、実際のオンラインカンファレンスの様子をリアルタイムで配信するシステムとして使われました。</p> <p><img src="https://64.media.tumblr.com/48eaf8e74149e7a64725ddea7d046f89/e962fe3b57d0d1ac-d7/s1280x1920/6a745d52f70fb176c96bdb68512f9721ffe70d95.png" alt="動画サムネイル" /><br /> <a target="_blank" rel="nofollow noopener" href="https://youtu.be/r_DiQTWEOwc">https://youtu.be/r_DiQTWEOwc</a></p> <h3 id="予告編 壱"><a href="#%E4%BA%88%E5%91%8A%E7%B7%A8+%E5%A3%B1">予告編 壱</a></h3> <p>上記内容の動画配信システムを作って配信する内容の電子奇書を技術書典10で頒布予定です。果たして原稿はあがるのか!? 乞うご期待。</p> <p><a target="_blank" rel="nofollow noopener" href="https://techbookfest.org/event/tbf10">技術書典10</a></p> <h3 id="予告編 弐"><a href="#%E4%BA%88%E5%91%8A%E7%B7%A8+%E5%BC%90">予告編 弐</a></h3> <p>上記GCPのGCEに作られたAMD Epyc インスタンスで動作するファンタスティックopenSUSEが、バックヤードで大活躍するとまことしやかに囁かれているフルオンラインカンファレンス、DojoCon Japan 2020。</p> <p>スタッフ一同 鋭意開催準備中です。</p> <p>2020年12月27日に、ご期待下さい。</p> <p><img src="https://64.media.tumblr.com/b5b5119da6a0652134aaeea340aa364f/e962fe3b57d0d1ac-b5/s640x960/b9be34f1835b022ae336e11c2a74ae85850d6b6d.png" alt="DojoConJapanImage" /></p> <p><a target="_blank" rel="nofollow noopener" href="https://dojocon2020.coderdojo.jp/">DojoCon Japan 2020 - Beyond the distance(距離を超えて) -</a></p> <h2 id="いかがでしたか?"><a href="#%E3%81%84%E3%81%8B%E3%81%8C%E3%81%A7%E3%81%97%E3%81%9F%E3%81%8B%EF%BC%9F">いかがでしたか?</a></h2> <p>全然詳解されていないし、GCPの年収、最終学歴も公表されていないようです。 調べてみましたが、結論はわかりませんでした!</p> <p>気に入ったらぜひ、いいね、チャンネル登録、金塊送付をしてくださいね!</p> <p>この記事は<a target="_blank" rel="nofollow noopener" href="https://adventar.org/calendars/5500">openSUSE Advent Calendar 2020 - Adventar</a>の12日目の投稿でした。</p> <p>ひきつづき、openSUSE Advent Calenderをお楽しみ下さい。</p> fkuMnk tag:crieit.net,2005:PublicArticle/16030 2020-08-14T23:54:11+09:00 2020-08-15T23:22:32+09:00 https://crieit.net/posts/Cloud-Run-Rate-exceeded Cloud RunでRate exceededエラーになる <p>ある日突然Cloud Runにデプロイしているサービス(当サービス)にアクセスすると無情にも「Rate exceeded.」とだけ表示されるようになっていた。エラーログを見てみるとステータスは429、エラー詳細を開くと「The request was aborted because there was no available instance」と表示されている。</p> <p>原因自体は初めてデプロイした時あたりにも出ていたのでわかる。Cloud Runには最大インスタンス数の設定があるのだが、それが足りないため。たしか最初は1~3あたりにしていたような気がする。それだと時々Rate exceededとなるため10くらいに増やしていた。それ以来自分は見ることがなくなった。</p> <p>しかし突然の再発。原因は分からないが、引き金はクローラのアクセスが集中したりしたのかもしれない。想像でしか無いが、ただ時々クローラがアクセスしてきてエラーが大量に出ているのは見かける。</p> <p>しかし今回は復旧する様子がない。22時くらいに発生し、色々と確認した。しかし原因はよく分からず。最大インスタンス数は20とか100とかにして試した気がするが、それでも復旧しなかった。原因が原因だけにもしかしたら放置しておけばいつの間にか治るかな、と思い、とりあえずねた。しかし次の日になっても治っていなかった。もしかすると時差の関係もあるのかなと思い一応夕方くらいまで待ってみたが、相変わらずだった。</p> <h2 id="解決した方法"><a href="#%E8%A7%A3%E6%B1%BA%E3%81%97%E3%81%9F%E6%96%B9%E6%B3%95">解決した方法</a></h2> <p>最終的に、最大インスタンス数の設定を1000にしたら動くようになった。さすがにそんなにアクセスが続いているわけもないと思うのでなぜそこまで上げなければならないのか結局よくわからないまま……。</p> <p>気づいたのは、Cloud Runにあるデモイメージを試してみたら動いたため。それは何の設定もいじっていなかったので最大インスタンス数が1000になっていた。</p> <p>とにかく困ったら上限の1000まで上げてみるとよいかもしれない。</p> <h2 id="今回は一時的な問題かも"><a href="#%E4%BB%8A%E5%9B%9E%E3%81%AF%E4%B8%80%E6%99%82%E7%9A%84%E3%81%AA%E5%95%8F%E9%A1%8C%E3%81%8B%E3%82%82">今回は一時的な問題かも</a></h2> <p>というか、今回のこれは僕以外も何人か発生してるのを観測したので一時的に発生している問題かもしれない。(多分書いている時点では未解決)</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/15913 2020-05-27T15:21:26+09:00 2020-05-27T15:21:26+09:00 https://crieit.net/posts/google-twilio-studio-rest-api-node-jp Googleスプレッドシートのシフト表を使ってTwilio Studioフローの転送先をNode.jsから更新する方法 <p><img src="https://twilio-cms-prod.s3.amazonaws.com/images/bequajswJOH0AUI_wEGCzYL1tE1Lk7xoDRK3nmBGdPsuLw.width-808.png" alt="Header" /><br /> <a target="_blank" rel="nofollow noopener" href="https://www.twilio.com/blog/call-forwarding-studio-remote-work">以前の記事</a>で、在宅勤務に伴う電話問い合わせの一時休止を解決する方法として、Twilio Studioを利用し個人電話に転送する方法を紹介しました。</p> <p><img src="https://twilio-cms-prod.s3.amazonaws.com/images/n6KNulbJGD3QxKIb-krEiNGnVjw963EqHHcaTmPpBLYAER.width-800.png" alt="Twilio Studio - Flow" /></p> <p>今回は<a target="_blank" rel="nofollow noopener" href="https://www.twilio.com/blog/load-data-from-google-spreadsheet-jp">別の記事</a>で紹介したGoogleスプレッドシートのシフトデータをもとに転送先となる個人をNode.jsで変更する方法を紹介します。</p> <p>前提条件</p> <ul> <li>Twilioアカウントを持っていること(<a target="_blank" rel="nofollow noopener" href="https://www.twilio.com/blog/how-to-create-twilio-account-jp">無料トライアルのサインアップ方法</a>)</li> <li>期間限定の問い合わせ番号となる<a target="_blank" rel="nofollow noopener" href="https://support.twilio.com/hc/en-us/articles/360044841214-Twilio-%E3%83%95%E3%83%AA%E3%83%BC%E3%83%88%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%AB%E3%82%A2%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%81%AB%E9%96%A2%E3%81%97%E3%81%A6#h_167b5625-0036-44e6-936f-108ed091cb80">電話番号を購入</a>していること<br /> (<a target="_blank" rel="nofollow noopener" href="https://support.twilio.com/hc/en-us/articles/360044400214-%E8%A6%8F%E5%88%B6%E6%83%85%E5%A0%B1%E3%81%AB%E9%96%A2%E3%82%8F%E3%82%8B%E6%9B%B8%E9%A1%9E%E3%81%AE%E6%8F%90%E5%87%BA%E6%96%B9%E6%B3%95">日本の番号を取得する場合</a>)</li> <li><a target="_blank" rel="nofollow noopener" href="https://www.twilio.com/blog/call-forwarding-studio-remote-work">こちらの記事</a>に則りフローを作成、公開済みであること</li> <li><a target="_blank" rel="nofollow noopener" href="https://www.twilio.com/blog/load-data-from-google-spreadsheet-jp">こちらの記事</a>に則りGoogleスプレッドシートからデータを取得するNode.jsアプリケーションを作成済みであること</li> </ul> <h2 id="Node.jsプロジェクトの作成とパッケージのインストール"><a href="#Node.js%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AE%E4%BD%9C%E6%88%90%E3%81%A8%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">Node.jsプロジェクトの作成とパッケージのインストール</a></h2> <p><a target="_blank" rel="nofollow noopener" href="https://www.twilio.com/blog/load-data-from-google-spreadsheet-jp">以前の記事</a>に沿って作成したNode.jsアプリケーションのフォルダーに移動し、<a target="_blank" rel="nofollow noopener" href="https://www.npmjs.com/package/twilio">twilio-node</a>パッケージをインストールします。</p> <pre><code>npm i twilio </code></pre> <p>次に.envファイルにTwilioへの接続情報やStudioフローのIDを保存する環境変数を追加します。</p> <pre><code>SPREADSHEET_ID= STAFF_WORKSHEET_ID= SHIFT_WORKSHEET_ID= TWILIO_ACCOUNT_SID= TWILIO_AUTH_TOKEN= TWILIO_STUDIO_FLOW_SID= </code></pre> <h2 id="Twilio Studio REST API v2を使ったフローの取得と更新"><a href="#Twilio+Studio+REST+API+v2%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E3%83%95%E3%83%AD%E3%83%BC%E3%81%AE%E5%8F%96%E5%BE%97%E3%81%A8%E6%9B%B4%E6%96%B0">Twilio Studio REST API v2を使ったフローの取得と更新</a></h2> <p>今回利用するTwilio Studio REST API v2は4月末に<a target="_blank" rel="nofollow noopener" href="https://www.twilio.com/blog/automate-flow-deployments-studio-rest-api-v2-beta">パブリックベータとしてアナウンス</a>されたばかりの機能です。この新しいAPIを使って定義済みのフロー設定を外部から更新できます。</p> <p><a target="_blank" rel="nofollow noopener" href="https://www.twilio.com/console">Twilioコンソール</a>を開きACCOUNT SIDと、AUTH TOKENをそれぞれ.envファイルの <code>TWILIO_ACCOUNT_SID</code>ならびに <code>TWILIO_STUDIO_FLOW_SID</code> の値として設定します。</p> <p><img src="https://twilio-cms-prod.s3.amazonaws.com/images/cfc6YMp-DykS55Rahs24kn2759AIZSMNsfhTto3dnHBibZ.width-800.png" alt="AccountSid & AuthToken" /></p> <p>次に、<a target="_blank" rel="nofollow noopener" href="https://www.twilio.com/console/studio/dashboard">Studioコンソール</a>を開き、call forwardingフローのSIDを <code>TWILIO_STUDIO_FLOW_SID</code> の値として設定します。</p> <p>index.jsを開き、<a target="_blank" rel="nofollow noopener" href="https://www.twilio.com/blog/load-data-from-google-spreadsheet-jp">前回の記事</a>でテストに使用したコードを変更します。このコードでは、シフト担当者の電話番号を取得した状態で、Twilio Nodeクライアントを利用しStudioフローを取得します。</p> <pre><code class="js">loadShiftPhoneNumbers().then ( numbers => { // twilio client const client = require('twilio') (process.env.TWILIO_ACCOUNTSID, process.env.TWILIO_AUTH_TOKEN); // Studioのフローを取得 client.studio.flows(process.env.TWILIO_STUDIO_FLOW_SID) .fetch() .then(flow => {}) .catch(error => console.error(error)) ;}) .catch( error => console.error(error)); </code></pre> <p>フローの定義情報は、definitionというプロパティに保持されているため、そちらを取得します。また、各ウィジェットについては、statesというプロパティに配列として定義されています。このstates配列からウィジェットの名前をキーとして着信を転送するウィジェットを取得し、更に転送先番号を更新します。</p> <pre><code class="js">loadShiftPhoneNumbers().then ( numbers => { // twilio client const client = require('twilio') (process.env.TWILIO_ACCOUNTSID, process.env.TWILIO_AUTH_TOKEN); // Studioのフローを取得 client.studio.flows(process.env.TWILIO_STUDIO_FLOW_SID) .fetch() .then(flow => { // フローの定義を取得 let definition = flow.definition; // forward_callウィジェットを取得 let callForwardWidget = definition.states.find( item => item.name == 'forward\_call'); // 転送先番号をシフトの電話番号で更新 callForwardWidget.properties.to = numbers; }) .catch(error => console.error(error)); }) .catch( error => console.error(error)); </code></pre> <p>後は更新した定義をStudio REST API v2を使い、反映させます。この際、statusプロパティで反映したフローを下書き状態(draft)にしておくことも、即座に公開(published)にすることもできます。</p> <pre><code class="js">loadShiftPhoneNumbers().then ( numbers => { // twilio client const client = require('twilio') (process.env.TWILIO_ACCOUNTSID, process.env.TWILIO_AUTH_TOKEN); // Studioのフローを取得 client.studio.flows(process.env.TWILIO_STUDIO_FLOW_SID) .fetch() .then(flow => { // フローの定義を取得 let definition = flow.definition; // forward_callウィジェットを取得 let callForwardWidget = definition.states.find( item => item.name == 'forward\_call'); // 転送先番号をシフトの電話番号で更新 callForwardWidget.properties.to = numbers; // 更新した定義を反映し、即座に公開 client.studio.flows(process.env.TWILIO_STUDIO_FLOW_SID) .update({ definition: definition, commitMessage: 'シフトの更新 - 2020/05/15', status: 'published'}) .then(res => console.log(res)) .catch(error => console.error(error)); }) .catch(error => console.error(error)); }) .catch( error => console.error(error)); </code></pre> <p>index.jsを実行し、ログにエラーが含まれていないこと、Studioのフローが実際に変更されていることを確認しましょう。</p> <pre><code>node index.js </code></pre> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>ご覧いただいたように、パブリックベータとして公開されたREST API v2を活用することで、外部のデータやシステムと連携した上でTwilio Studioのフローを更新することができるようになりました。非常に強力なAPIなので、ぜひご活用ください。</p> <p>今回のサンプルはこちらの<a target="_blank" rel="nofollow noopener" href="https://github.com/neri78/twilio-studio-google-spreadsheet">GitHubリポジトリ</a>からクローンし、環境変数にそれぞれ値を設定することで確認することも可能です。</p> <h2 id="新型コロナウイルス感染症への支援策について"><a href="#%E6%96%B0%E5%9E%8B%E3%82%B3%E3%83%AD%E3%83%8A%E3%82%A6%E3%82%A4%E3%83%AB%E3%82%B9%E6%84%9F%E6%9F%93%E7%97%87%E3%81%B8%E3%81%AE%E6%94%AF%E6%8F%B4%E7%AD%96%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">新型コロナウイルス感染症への支援策について</a></h2> <p>Twilioでは新型コロナウィルス感染症により引き起こされるさまざまな社会問題を解決する会社、団体、開発者グループに向けて無料クレジットの進呈など支援を行なっています。詳しくは<a target="_blank" rel="nofollow noopener" href="https://www.twilio.com/blog/covid-19-response-japan">こちらの記事</a>をご覧ください。</p> <p>また、Twilioを自社のシステム、ソリューションやパッケージに組み込みたいとお考えの場合は、<a target="_blank" rel="nofollow noopener" href="https://www.twilio.com/japan/help/sales">営業部までお問い合わせ</a>ください。</p> <h2 id="このエントリについての問い合わせ"><a href="#%E3%81%93%E3%81%AE%E3%82%A8%E3%83%B3%E3%83%88%E3%83%AA%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E3%81%AE%E5%95%8F%E3%81%84%E5%90%88%E3%82%8F%E3%81%9B">このエントリについての問い合わせ</a></h2> <p>不明点があればぜひ、お問い合わせください。オンライン登壇のご依頼等もこちらまで!</p> <ul> <li>Twitter (<a target="_blank" rel="nofollow noopener" href="https://twitter.com/neri78">@Neri78</a>)</li> <li>Email: <a target="_blank" rel="nofollow noopener" href="mailto:dikehara@twilio.com">[email protected]</a></li> <li>Github: <a target="_blank" rel="nofollow noopener" href="https://github.com/neri78">https://github.com/neri78</a></li> <li>Twitch: <a target="_blank" rel="nofollow noopener" href="https://twitch.tv/neri78">https://twitch.tv/neri78</a></li> </ul> Neri78 tag:crieit.net,2005:PublicArticle/15903 2020-05-20T16:34:57+09:00 2020-05-20T18:07:54+09:00 https://crieit.net/posts/google-spreadsheet-sheets-api GoogleスプレッドシートからNode.jsでシフトデータを読み出す方法 <p><img src="https://twilio-cms-prod.s3.amazonaws.com/images/JfSEBIrPI4CAu3k18bqViRLlvPl1fZIbJ9LpKwl1J86O0d.width-808.png" alt="Header Image" /><br /> <a target="_blank" rel="nofollow noopener" href="https://console.cloud.google.com/?hl=ja">Google Cloud Platform(GCP)</a>には<a target="_blank" rel="nofollow noopener" href="https://developers.google.com/sheets/api">Google Sheets API</a>が提供されており、このAPIを利用してGoogleスプレッドシートのデータにアクセスすることができます。今回はGoogleスプレッドシートのスタッフ、シフトデータをNode.jsで読み込む方法を紹介します。</p> <p>前提条件</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://console.cloud.google.com/?hl=ja">Google Cloud Platform (GCP)のアカウント</a>の作成、ならびに有効な支払い方法が登録されていること</li> <li><a target="_blank" rel="nofollow noopener" href="https://www.google.com/intl/ja_jp/sheets/about/">Googleスプレッドシート</a>を利用できること</li> </ul> <h2 id="シフトを管理するGoogleスプレッドシート"><a href="#%E3%82%B7%E3%83%95%E3%83%88%E3%82%92%E7%AE%A1%E7%90%86%E3%81%99%E3%82%8BGoogle%E3%82%B9%E3%83%97%E3%83%AC%E3%83%83%E3%83%89%E3%82%B7%E3%83%BC%E3%83%88">シフトを管理するGoogleスプレッドシート</a></h2> <p><a target="_blank" rel="nofollow noopener" href="https://docs.google.com/spreadsheets/d/1KHozXisufSbldqeTtkTO3-fRT9McdVxrzVz7YyCWSqM/edit?usp=sharing">こちら</a>にスプレッドシートのサンプルを用意しました。ファイルメニューからこのスプレッドシートを自分のGoogleアカウントで利用できるようにコピーします。スプレッドシートの中身をみてみましょう。Shiftシートには日ごとの担当者を4名まで設定しています。<br /> <img src="https://twilio-cms-prod.s3.amazonaws.com/images/JTcbF8FiG0AyceVQcR4FQNszfxEwj5zwFtf9w0KPLfcwJj.width-800.png" alt="Google Spreadsheet - Shift" /></p> <p>また、Staffシートには担当者ごとの連絡先電話番号が<a target="_blank" rel="nofollow noopener" href="https://www.twilio.com/docs/glossary/what-e164">E.164フォーマット</a>で登録されています。</p> <p><img src="https://twilio-cms-prod.s3.amazonaws.com/images/-ke-JpIzwIkEdVu41E8aa4OsC8YPLq9zHavppvy7FuI04C.width-800.png" alt="Google Spreadsheet - Staff" /></p> <h2 id="GCPでSheets APIを有効化"><a href="#GCP%E3%81%A7Sheets+API%E3%82%92%E6%9C%89%E5%8A%B9%E5%8C%96">GCPでSheets APIを有効化</a></h2> <p>はじめてGCPを利用する場合は、<a target="_blank" rel="nofollow noopener" href="https://console.cloud.google.com/cloud-resource-manager">コンソール</a>からプロジェクトを作成します。<br /> <img src="https://twilio-cms-prod.s3.amazonaws.com/images/ooE7wJ3JEVutwUGFPfuZC9JorRaxWpFOD4K4DS9syz0L99.width-800.png" alt="GCP - Create a project" /></p> <p>例ではプロジェクト名を <code>google-sheet-studio</code> としましたが、任意のプロジェクト名で構いません。<br /> <img src="https://twilio-cms-prod.s3.amazonaws.com/images/AfZdHBVKjtKyGBsHpFbVGErsr-LOfmrkXp5xIYYN0hLnU0.width-800.png" alt="GCP - project name" /></p> <p>作成ボタンをクリックするとリソースの管理画面に戻り、プロジェクトの作成が開始されます。数十秒〜数分程度で作成が完了します。</p> <p>次に<a target="_blank" rel="nofollow noopener" href="https://console.cloud.google.com/apis/library">API ライブラリ</a>を開きます。</p> <p><img src="https://twilio-cms-prod.s3.amazonaws.com/images/GDhetd6rJRyWJZNxq1leRhhn7bwz3hqWkj74w0eeSCHQhv.width-800.png" alt="GCP - Open API Library" /></p> <p>先ほど作成したプロジェクトが選択されていることを確認します。</p> <p><img src="https://twilio-cms-prod.s3.amazonaws.com/images/F085blQIr1lxDfm7NuuO1Om1XrHR8RUZazZMvc0CRydar-.width-800.png" alt="GCP - API Library with a project" /></p> <p>Google Sheets APIを検索し、プロジェクトに追加します。</p> <p><img src="https://twilio-cms-prod.s3.amazonaws.com/images/5QjQstd86zQXHcCP_oPQVO5uIvSOipkjGwBqZjTQyKcEpL.width-800.png" alt="GCP - search sheets API" /></p> <p>詳細画面から <code>有効にする</code> ボタンをクリックするとGoogle Sheets APIが有効になります。</p> <p><img src="https://twilio-cms-prod.s3.amazonaws.com/images/iHS-ff4E5U65OLwx-Hz52VM2VCeCDb14rjwmseU2cb3C1W.width-800.png" alt="GCP - enable sheets API" /></p> <p>APIが有効化されると、概要画面に遷移します。次に <code>認証情報を作成</code> ボタンをクリックし、このAPIを使用するための認証情報を作成します。</p> <p><img src="https://twilio-cms-prod.s3.amazonaws.com/images/mdPFFkjpFUewRvZtgR4HhhwNtONnuvGvs4o3Mbb8YWXGnT.width-800.png" alt="GCP - Add auth info" /></p> <p>認証情報の追加画面において次の設定を行い、<code>必要な認証情報</code> ボタンをクリックします。</p> <ul> <li>使用する API - Google Sheets API</li> <li>API を呼び出す場所 - ウェブサーバー(node.js、Tomcat など)</li> <li>アクセスするデータの種類 - アプリケーション データ</li> <li>App Engine または Compute Engine でこの API を使用する予定はありますか? - いいえ、使用していません</li> </ul> <p><img src="https://twilio-cms-prod.s3.amazonaws.com/images/d7DzQucz1snBQJBnUZ8AxaWun3kguQxe8_xf6HS2NrjFgr.width-800.png" alt="GCP - Create a service account" /></p> <p>続けてサービスアカウント名とロールを設定します。例では、<code>test</code> およびロールを <code>Project</code> の <code>閲覧者</code> とし、キーのタイプを <code>JSON</code> としました。</p> <p><img src="https://twilio-cms-prod.s3.amazonaws.com/images/y-iIsGp2LwAvFexgqbUx_lANXcg-bhKlka14JOcK1sb97D.width-800.png" alt="GCP - Create a service account - name" /></p> <p><code>次へ</code> ボタンをクリックすると認証情報を含んだJSONファイルが作成されダウンロードされます。このファイルはGoogle Sheets APIを利用するために必要になります。作成されたJSONファイルを開くと <code>client_email</code> という名前のキーの値に先ほど作成したサービス アカウント IDが記載されています。Googleスプレッドシートを共有する際にこの情報が必要になります。</p> <p><img src="https://twilio-cms-prod.s3.amazonaws.com/images/JgW7p51hA5u-4yggqHymFjLMI_rGBvu0wAHDCpVJXsZeJq.width-800.png" alt="gcp - service account" /></p> <h2 id="Googleスプレッドシートの共有とURLや情報の確認"><a href="#Google%E3%82%B9%E3%83%97%E3%83%AC%E3%83%83%E3%83%89%E3%82%B7%E3%83%BC%E3%83%88%E3%81%AE%E5%85%B1%E6%9C%89%E3%81%A8URL%E3%82%84%E6%83%85%E5%A0%B1%E3%81%AE%E7%A2%BA%E8%AA%8D">Googleスプレッドシートの共有とURLや情報の確認</a></h2> <p>次に、Google Sheets APIからアクセスをできるようにGoogleスプレッドシートをサービス アカウントに共有します。先ほど複製したGoogleスプレッドシートを開き、右上の <code>共有</code> ボタンをクリックします。表示された共有ダイアログに先ほどのサービス アカウント IDを入力します。</p> <p><img src="https://twilio-cms-prod.s3.amazonaws.com/images/eNfWeKahkSszuRfCxD4PgtaVRVJm-vLmfv19RvvXM4xgxb.width-800.png" alt="Google Spreadsheet - share the sheet" /></p> <p>Enterキーを押すと、権限の設定を行えます。書き込み権限は必要ないため閲覧者としました。<code>共有</code> ボタンをクリックし、共有を完了します。</p> <p><img src="https://twilio-cms-prod.s3.amazonaws.com/images/z5tAPOALrfoTztQVwEDWn1fmusPZP25PbsepJd8VsMp8P7.width-800.png" alt="Google Spreadsheet - share as a viewer" /></p> <p>更に、このGoogleスプレッドシートから次の情報を控えておきます。</p> <ul> <li>スプレッドシートID(https://docs.google.com/spreadsheets/d/ の後に表示されている英数文字列のうち、次の’/’ の前の値。例: https://docs.google.com/spreadsheets/d/ <strong>12312321xxx21232131212</strong> /edit#gid=0 の太字部分)</li> <li>Shift、StaffそれぞれのワークシートのID(URLが <strong>#gid=0</strong> の場合は、 <strong>0</strong> となる )</li> </ul> <p>これでシートから情報を取得する前準備が整いました。</p> <h2 id="Node.jsプロジェクトの作成とパッケージのインストール"><a href="#Node.js%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AE%E4%BD%9C%E6%88%90%E3%81%A8%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">Node.jsプロジェクトの作成とパッケージのインストール</a></h2> <p><a target="_blank" rel="nofollow noopener" href="https://developers.google.com/sheets/api">Google Sheets API</a>を利用することでGoogleスプレッドシートのデータにアクセスすることができます。このAPIに対応する<a target="_blank" rel="nofollow noopener" href="https://github.com/googleapis/google-api-nodejs-client/tree/master/src/apis/sheets">Node.jsクライアントライブラリ</a>も用意されており、<a target="_blank" rel="nofollow noopener" href="https://developers.google.com/sheets/api/quickstart/nodejs">クイックスタート</a>のようにセルの値を取得することもできるのですが、取得するセルの範囲を指定する必要があり、使いにくいと感じるかもしれません。そのため、今回はGoogle Sheets APIを使いやすくラップした<a target="_blank" rel="nofollow noopener" href="https://developers.google.com/sheets/api/quickstart/nodejs">google-spreadsheet</a>パッケージを利用します。このパッケージを利用すると、セルの範囲を指定することなく、ワークシートから行オブジェクトとしてデータを読み込むことができます。</p> <p>Node.jsアプリケーションを作成し、<a target="_blank" rel="nofollow noopener" href="https://www.npmjs.com/package/google-spreadsheet">google-spreadsheet</a>と環境変数を.envファイルからロードできる<a target="_blank" rel="nofollow noopener" href="https://www.npmjs.com/package/dotenv">dotenv</a>パッケージをインストールします。</p> <pre><code class="bash">npm i google-spreadsheet dotenv </code></pre> <p>次にGoogleスプレッドシートやシートのIDを記録しておく.envファイルを作成します。</p> <pre><code class="bash">touch .env </code></pre> <p>.envファイルには次の環境変数を追加しておきます。</p> <pre><code>SPREADSHEET_ID= SHIFT_WORKSHEET_ID= STAFF_WORKSHEET_ID= </code></pre> <p><code>SPREADSHEET_ID</code>、<code>STAFF_WORKSHEET_ID</code>、<code>SHIFT_WORKSHEET_ID</code> には先ほど控えておいたGoogleスプレッドシートのIDやそれぞれのシートのIDを追加します。</p> <p>最後にGCPからダウンロードしたJSONファイルをプロジェクトフォルダーにコピーし、わかりやすいように名前を <code>credentials.json</code> と変更します。これで準備完了です。</p> <h2 id="Googleスプレッドシートからシフト表を取得"><a href="#Google%E3%82%B9%E3%83%97%E3%83%AC%E3%83%83%E3%83%89%E3%82%B7%E3%83%BC%E3%83%88%E3%81%8B%E3%82%89%E3%82%B7%E3%83%95%E3%83%88%E8%A1%A8%E3%82%92%E5%8F%96%E5%BE%97">Googleスプレッドシートからシフト表を取得</a></h2> <p>ここからはGoogleスプレッドシートからシフト表を取得するコードを実装します。Node.jsアプリケーションに新しくjsファイルを追加します。<code>index.js</code> という名前で作成しました。</p> <pre><code class="bash">touch index.js </code></pre> <p>index.jsをエディタで開き、環境変数の読み込みや必要なパッケージをインポートします。</p> <pre><code class="js">'use strict'; require('dotenv').config(); const { GoogleSpreadsheet } = require('google-spreadsheet'); </code></pre> <p>次にGoogleスプレッドシートからシフトデータを読み取り、担当者の電話番号を返す非同期関数を実装します。</p> <pre><code class="js">// Googleスプレッドシートからシフト情報をロードし、担当者の電話番号を取得 async function loadShiftPhoneNumbers() { // 処理を実装 } </code></pre> <p>この <code>loadShiftPhoneNumbers</code> 関数でGoogleスプレッドシートをロードします。ここでGCPへの接続に必要になるのが先ほどコピーし、名前を変更した <code>credentials.json</code> です。</p> <pre><code class="js">// Googleスプレッドシートからシフト情報をロードし、担当者の電話番号を取得 async function loadShiftPhoneNumbers() { // スプレッドシートIDと資格情報を用いてGoogleスプレッドシートをロード const doc = new GoogleSpreadsheet(process.env.SPREADSHEET\_ID); const credentials = require('./credentials.json'); await doc.useServiceAccountAuth(credentials); await doc.loadInfo(); } </code></pre> <p>ワークシートを取得する場合は、<a target="_blank" rel="nofollow noopener" href="https://theoephraim.github.io/node-google-spreadsheet/#/classes/google-spreadsheet?id=worksheets">GoogleSpreadsheet.sheetsById、またはGoogleSpreadsheet.sheetsbyIndex</a>を利用できます。さらに、<a target="_blank" rel="nofollow noopener" href="https://theoephraim.github.io/node-google-spreadsheet/#/classes/google-spreadsheet-worksheet?id=fn-getrows">GoogleSpreadsheetWorksheet.getRows</a>メソッドを使用し、ワークシートの行を取得できます。残念ながら特定の列の値をキーにフィルタリングはできないようなので全ての行を取得します。</p> <pre><code class="js">// Googleスプレッドシートからシフト情報をロードし、担当者の電話番号を取得 async function loadShiftPhoneNumbers() { // スプレッドシートIDと資格情報を用いてGoogleスプレッドシートをロード const doc = new GoogleSpreadsheet(process.env.SPREADSHEET\_ID); const credentials = require('./credentials.json'); await doc.useServiceAccountAuth(credentials); await doc.loadInfo(); //シフト情報を取得 const shiftSheet = await doc.sheetsById[process.env.SHIFT_WORKSHEET_ID]; const shiftRows = await shiftSheet.getRows(); // 従業員情報を取得 const staffSheet = await doc.sheetsById[process.env.STAFF_WORKSHEET_ID]; const staffRows = await staffSheet.getRows(); } </code></pre> <p><a target="_blank" rel="nofollow noopener" href="https://theoephraim.github.io/node-google-spreadsheet/#/classes/google-spreadsheet-worksheet?id=fn-getrows">GoogleSpreadsheetWorksheet.getRows</a>メソッドはGoogleSpreadsheetRowの配列を返します。また、この<a target="_blank" rel="nofollow noopener" href="https://theoephraim.github.io/node-google-spreadsheet/#/classes/google-spreadsheet-row">GoogleSpreadsheetRow</a>オブジェクトは最初の行をプロパティのキーとしてアクセスできるため、<a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/find">Array.prototype.find()</a>メソッドを利用し、Date列をキーとして特定の日付のデータを抜き出すことができます。この記事では、2020年5月15日を例として取得します。実際のアプリケーションでは <code>new Date()</code> などを利用し、当日のデータを取得することになるでしょう。</p> <pre><code class="js">// Googleスプレッドシートからシフト情報をロードし、担当者の電話番号を取得 async function loadShiftPhoneNumbers() { // スプレッドシートIDと資格情報を用いてGoogleスプレッドシートをロード const doc = new GoogleSpreadsheet(process.env.SPREADSHEET\_ID); const credentials = require('./credentials.json'); await doc.useServiceAccountAuth(credentials); await doc.loadInfo(); //シフト情報を取得 const shiftSheet = await doc.sheetsById[process.env.SHIFT_WORKSHEET_ID]; const shiftRows = await shiftSheet.getRows(); // 従業員情報を取得 const staffSheet = await doc.sheetsById[process.env.STAFF_WORKSHEET_ID]; const staffRows = await staffSheet.getRows(); // シフト情報からDate列の値と指定した日付をロケール情報に基づいて取得 let shiftRow = shiftRows.find(row => new Date(row.Date).toLocaleDateString() === new Date('2020/5/15').toLocaleDateString()); } </code></pre> <p>あとは、取得した行から必要なデータを読み取り、アプリケーションで使用できます。</p> <p>データの活用例として、このシフトデータから担当者の電話番号をカンマ区切りの文字列で取得する方法も実装します。</p> <p><code>shiftRow.Employee1</code>のように各列のキーを指定してデータを取得することもできますが、<code>shiftRow._rawData shiftRow</code> には、行のデータが配列として保持されています。2020年5月15日のデータは、<code>['5/15/2020', 'Mitsuharu', 'Yoshihiro']</code> となります。この配列を<a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/slice">Array.prototype.slice()</a>メソッドで最初の日付データを除外した配列とし、さらに、<a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map">Array.prototype.map()</a>メソッドでシフト担当の従業員の電話番号の配列へと変換します。そして、最後に、<a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/join">Array.prototype.join()</a>メソッドで文字列として返すという処理を実装しました。</p> <pre><code class="js">// Googleスプレッドシートからシフト情報をロードし、担当者の電話番号を取得 async function loadShiftPhoneNumbers() { // スプレッドシートIDと資格情報を用いてGoogleスプレッドシートをロード const doc = new GoogleSpreadsheet(process.env.SPREADSHEET\_ID); const credentials = require('./credentials.json'); await doc.useServiceAccountAuth(credentials); await doc.loadInfo(); //シフト情報を取得 const shiftSheet = await doc.sheetsById[process.env.SHIFT_WORKSHEET_ID]; const shiftRows = await shiftSheet.getRows(); // 従業員情報を取得 const staffSheet = await doc.sheetsById[process.env.STAFF_WORKSHEET_ID]; const staffRows = await staffSheet.getRows(); // シフト情報からDate列の値と指定した日付をロケール情報に基づいて取得 let shiftRow = shiftRows.find(row => new Date(row.Date).toLocaleDateString() === new Date('2020/5/15').toLocaleDateString()); // 元データ['5/15/2020', 'Mitsuharu', 'Yoshihiro'] // Date列(最初の列)を取り除き、シフト担当の従業員を含む配列を取得する let employeesOnDuty = shiftRow._rawData.slice(1); // ['Mitsuharu', 'Yoshihiro'] // 名前から電話番号の配列に置換 employeesOnDuty = employeesOnDuty.map(m => staffRows.find(row => row.Name === m).PhoneNumber); // ['+815012341235', '+815012341237'] return employeesOnDuty.join(',');} </code></pre> <p>ここまで実装を終えた段階で、きちんとデータを読み込めるかどうかを確認しましょう。<br /> loadShiftNumbers関数のスコープ外に次のコードを追加します。</p> <pre><code class="js">// 実装した関数が正しく動作するかテスト loadShiftPhoneNumbers() .then (numbers => console.log(numbers)) .catch(error => console.error(error)); </code></pre> <p>index.jsを実行し、次のような結果がコンソールに出力されていれば成功です。</p> <pre><code>node index.js </code></pre> <p>実行結果</p> <pre><code>+815012341235,+815012341237 </code></pre> <p>想定した結果が得られない場合は、出力されたエラーを参考にGCPの設定や、JSONファイルの読み込みなどを確認してください。</p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>ご覧いただいたように、Google Sheets APIを使うことでGoogleスプレッドシートをデータソースとしたアプリケーションを構築することができます。ぜひご活用ください。</p> <h2 id="このエントリについての問い合わせ"><a href="#%E3%81%93%E3%81%AE%E3%82%A8%E3%83%B3%E3%83%88%E3%83%AA%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E3%81%AE%E5%95%8F%E3%81%84%E5%90%88%E3%82%8F%E3%81%9B">このエントリについての問い合わせ</a></h2> <p>不明点があればぜひ、お問い合わせください。オンライン登壇のご依頼等もこちらまで!</p> <ul> <li>Twitter (<a target="_blank" rel="nofollow noopener" href="https://twitter.com/neri78">@Neri78</a>)</li> <li>Email: <a target="_blank" rel="nofollow noopener" href="mailto:dikehara@twilio.com">[email protected]</a></li> <li>Github: <a target="_blank" rel="nofollow noopener" href="https://github.com/neri78">https://github.com/neri78</a></li> <li>Twitch: <a target="_blank" rel="nofollow noopener" href="https://twitch.tv/neri78">https://twitch.tv/neri78</a></li> </ul> Neri78 tag:crieit.net,2005:PublicArticle/15775 2020-03-20T13:51:56+09:00 2020-03-22T06:54:01+09:00 https://crieit.net/posts/Nuxt-5-Firebase-GAE-Netlify-Heroku Nuxtアプリを無料で公開するときに試した5つの環境まとめ(Firebase/GAE/Netlify/Heroku) <p>最近Nuxtでいろいろ作っているけど、無料で使える環境をいろいろ試してる。<br /> いろいろメリデメあるけど、SPAならNetlify/SSRならHerokuがよさそう。<br /> いままで試したものをまとめてみた。</p> <h3 id="ほしかったもの"><a href="#%E3%81%BB%E3%81%97%E3%81%8B%E3%81%A3%E3%81%9F%E3%82%82%E3%81%AE">ほしかったもの</a></h3> <p>主に開発してるのが<a target="_blank" rel="nofollow noopener" href="https://tsundoku.site">CGM系のWebサービス</a>なので、</p> <ol> <li>動的なOGP画像などが設定できる(OGP芸)</li> <li>カスタムドメインが使える</li> <li>日次のランキング集計などの定期実行ができる</li> </ol> <p>が、無料でできて、なるべく実装が楽で、そこまで遅くないのがうれしい。</p> <h3 id="試した5つのパターン"><a href="#%E8%A9%A6%E3%81%97%E3%81%9F5%E3%81%A4%E3%81%AE%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3">試した5つのパターン</a></h3> <p>試したのは以下の5パターン。試してみた順で記載。</p> <ol> <li>Nuxt(SSR) + Cloud Function<br /> 起動がかなり遅かった。。実装も大変なのでNG</li> <li>Nuxt(SPA) + Firebase Hosting<br /> 構築はかなり楽。ただ、OGP芸が大変でFunctionsが必要</li> <li>Nuxt(SPA) + Netlify<br /> プレレンダリングでOGP芸が楽。定期実行はFunctionsでできる</li> <li>Nuxt(SSR) + GAE(f1:256M)<br /> メモリの制限きつく、たまに落ちる。。定期実行はcron.yamlでできる</li> <li>Nuxt(SSR) + Heroku(free:512M) + Cloudflare<br /> メモリ多くてよい。SSLはないのでCloudflareを併用。定期実行はHeroku Scheduler</li> </ol> <p>SPAで十分であれば、「3.Nuxt(SPA) + Netlify」が構築も簡単で良かった。<br /> <a target="_blank" rel="nofollow noopener" href="https://tsundoku.site">積読ハウマッチ</a>は、現在この構成。</p> <p>SSRの場合、「5. Nuxt(SSR) + Heroku(free:512M) + CloudFlare」が良い感じ。<br /> <a target="_blank" rel="nofollow noopener" href="https://hen-ai.net/">へんあいマップ</a>がこの構成。</p> <h3 id="各パターンについて"><a href="#%E5%90%84%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">各パターンについて</a></h3> <h4 id="1. Nuxt(SSR) + Cloud Function"><a href="#1.+Nuxt%28SSR%29+%2B+Cloud+Function">1. Nuxt(SSR) + Cloud Function</a></h4> <p>一番はじめに<a target="_blank" rel="nofollow noopener" href="https://tsundoku.site">積読ハウマッチ</a>でやろうとした構成。</p> <p><img width="870" alt="スクリーンショット 2020-03-20 11.43.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/7fa5a956-cec1-9117-1d5d-f769eae53a32.png"></p> <p>細かいやり方は、以下の記事の「Firebase Cloud Functionsの設定してSSRできるようにする」あたりに。<br /> ・<a target="_blank" rel="nofollow noopener" href="https://www.memory-lovers.blog/entry/2019/04/02/115149">Nuxt.jsではじめるときのやることリスト(SSRも国際化も自動デプロイも) - くらげになりたい。</a></p> <p>当時は動的ページのSEO対応するには、この方法が多く検索に出ていたので試したけど、<br /> Cloud Functionのコールドスタートがつらすぎてお蔵入り。。SPAでいくことに。。</p> <h4 id="2. Nuxt(SPA) + Firebase Hosting"><a href="#2.+Nuxt%28SPA%29+%2B+Firebase+Hosting">2. Nuxt(SPA) + Firebase Hosting</a></h4> <p><a target="_blank" rel="nofollow noopener" href="https://tsundoku.site">積読ハウマッチ</a>をリリースしたときの構成。</p> <p><img width="910" alt="スクリーンショット 2020-03-20 11.37.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/37459683-872a-5047-a383-71c33f0c640e.png"></p> <p>課題だった動的ページのSEOは、Cloud Functionsを経由して返す方法で対応。<br /> こちらも当時よく検索に出てたけど、実装が大変そうだったので2番手に。</p> <p>細かいやり方は、以下の記事に。(2020/03/22追記: OGP画像生成系の記事を追加)<br /> ・<a target="_blank" rel="nofollow noopener" href="https://www.memory-lovers.blog/entry/2019/08/07/150000">Nuxt(SPA)+FirebaseでSEO!OGP!: 特定のパスだけheadだけ返すやつ - くらげになりたい。</a><br /> ・<a target="_blank" rel="nofollow noopener" href="https://qiita.com/kira_puka/items/8c1d1240c3aa200cbec0">Nuxt.js(SPA)+Firebaseで積読用の読書管理サービスを作ってみたときにハマったこと - Qiita</a><br /> ・<a target="_blank" rel="nofollow noopener" href="https://www.memory-lovers.blog/entry/2019/06/26/194500">Cloud Functions + ImageMagickでOPG画像の動的生成してCloud Storageにアップロードする - くらげになりたい。</a><br /> ・<a target="_blank" rel="nofollow noopener" href="https://www.memory-lovers.blog/entry/2020/02/19/150000">Cloud FunctionとSVGでOGP画像生成を試行錯誤したまとめ - くらげになりたい。</a></p> <p>カスタムドメインについては、Firebase HostingでSSLと合わせて無料で設定可能。</p> <p>定期実行は、Cloud Functionsでできるのでそれを利用した。<br /> ・<a target="_blank" rel="nofollow noopener" href="https://firebase.google.com/docs/functions/schedule-functions?hl=ja">関数のスケジュール設定  |  Firebase</a><br /> ・<a target="_blank" rel="nofollow noopener" href="https://qiita.com/kira_puka/items/1f164dd8d1a5a281d9c1">Cloud Functions for Firebaseのcronみたいな定期実行を試したら簡単だった - Qiita</a></p> <p>ただ、Cloud Functionsの定期実行は、<br /> 「<strong>Googleアカウントごとに3つのジョブ</strong>を無料で使用できる」<br /> なので、注意が必要。<strong>プロジェクトごとじゃない</strong>。。</p> <h4 id="3. Nuxt(SPA) + Netlify"><a href="#3.+Nuxt%28SPA%29+%2B+Netlify">3. Nuxt(SPA) + Netlify</a></h4> <p><a target="_blank" rel="nofollow noopener" href="https://tsundoku.site">積読ハウマッチ</a>の現在の構成。</p> <p><img width="775" alt="スクリーンショット 2020-03-20 11.47.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/5010c13a-98a9-c9e0-ae3b-767d18cd8006.png"></p> <p><a target="_blank" rel="nofollow noopener" href="https://docs.netlify.com/site-deploys/post-processing/prerendering/#set-up-prerendering">NetlifyのPrerendering</a>が無料化されて使えるようになり、よいという話を聞くように。。</p> <p>実装が複雑で、変更もしにくかったので、この方法に。<br /> Netlify自体がCDNも提供していているので、すこしはやくなった(気がする)</p> <p>カスタムドメインも、NetlifyのDNSを設定して無料で対応できる。</p> <p>定期実行は、2.と同じ感じで、Cloud Functionsのまま。</p> <p>コード量も減って変更もしやすくなったので、OGP画像の改善とかが楽にできるように。。(<em>´ω`</em>)</p> <h4 id="4. Nuxt(SSR) + GAE(f1:256M)"><a href="#4.+Nuxt%28SSR%29+%2B+GAE%28f1%3A256M%29">4. Nuxt(SSR) + GAE(f1:256M)</a></h4> <p>SPAの課題として、初期表示が遅いのでなんとかしたいなと、SSRの環境を模索しはじめ。。<br /> 公開していないけど、1つ作ってみた。</p> <p><img width="798" alt="スクリーンショット 2020-03-20 13.17.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/c24ce0b2-64b3-1ea4-9bd2-e2150ba13d14.png"></p> <p>試してみたところ、起動するだけでメモリ上限すれすれで、複数アクセスがあったりすると、落ちる場合も。。<br /> (ts-nodeで動かしているのも悪い気がしている。。)</p> <p><img width="561" alt="スクリーンショット 2020-03-20 12.22.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/e3940627-4141-4c17-3c82-b2ee13ca1e14.png"></p> <p>ただ、定期実行はcron.yamlを用意すればURLに送信でき、無料範囲も広い。<br /> 料金も「<a target="_blank" rel="nofollow noopener" href="https://cloud.google.com/appengine/pricing?hl=ja#%E3%81%9D%E3%81%AE%E4%BB%96%E3%81%AE%E3%83%AA%E3%82%BD%E3%83%BC%E3%82%B9">その他のリソース</a>」をみるとcronは無料のよう。<br /> ・<a target="_blank" rel="nofollow noopener" href="https://cloud.google.com/appengine/docs/flexible/nodejs/scheduling-jobs-with-cron-yaml?hl=ja">cron.yaml を使用したジョブのスケジューリング</a></p> <p>カスタムドメインやSSLも無料で利用できる感じ。(試してないので未確認)</p> <h4 id="5. Nuxt(SSR) + Heroku(free:512M) + Cloudflare"><a href="#5.+Nuxt%28SSR%29+%2B+Heroku%28free%3A512M%29+%2B+Cloudflare">5. Nuxt(SSR) + Heroku(free:512M) + Cloudflare</a></h4> <p>GAEでうまくいかなかったので、無料でメモリも多いHerokuを利用。<br /> <a target="_blank" rel="nofollow noopener" href="https://hen-ai.net/">へんあいマップ</a>がこの構成で稼働中。</p> <p><img width="885" alt="スクリーンショット 2020-03-20 13.24.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/60f2ab5c-3f4a-9b4b-ac45-341ed99c4667.png"></p> <p>定期実行は無料のアドオン(<a target="_blank" rel="nofollow noopener" href="https://elements.heroku.com/addons/scheduler">Heroku Scheduler</a>)が利用できる。<br /> Nuxt側で<a target="_blank" rel="nofollow noopener" href="https://ja.nuxtjs.org/api/configuration-servermiddleware/">serverMiddleware</a>を用意すればOK。</p> <p>ただ、メモリは多く定期実行もが、Herokuの無料枠だと制限も多い。</p> <ol> <li>SSLは非対応</li> <li>30分アクセスがないとスリープする</li> <li>クレジットカードの登録で1000時間/月xアカウント<br /> (未認証だと550時間/月xアカウント)</li> </ol> <h5 id="1. SSLは非対応"><a href="#1.+SSL%E3%81%AF%E9%9D%9E%E5%AF%BE%E5%BF%9C">1. SSLは非対応</a></h5> <p>単体だけだとSSLに対応していないので、<a target="_blank" rel="nofollow noopener" href="https://www.cloudflare.com/ja-jp/">Cloudflare</a>を併用。<br /> CloudflareがCDNも提供してくれるので良い感じに。</p> <h5 id="2. 30分アクセスがないとスリープする"><a href="#2.+30%E5%88%86%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%8C%E3%81%AA%E3%81%84%E3%81%A8%E3%82%B9%E3%83%AA%E3%83%BC%E3%83%97%E3%81%99%E3%82%8B">2. 30分アクセスがないとスリープする</a></h5> <p>これは、Heroku Schedulerを使えばOK。<br /> 任意のURLを叩けるため、15分毎などスリープしないようにしておく。</p> <h5 id="3. 無料枠は1000時間/月xアカウント"><a href="#3.+%E7%84%A1%E6%96%99%E6%9E%A0%E3%81%AF1000%E6%99%82%E9%96%93%2F%E6%9C%88x%E3%82%A2%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88">3. 無料枠は1000時間/月xアカウント</a></h5> <p>1000時間あれば、24時間x31日でも744時間なので、大丈夫な感じ。<br /> ただ、アカウント単位での無料枠なので、複数アプリを無料で稼働はできない。。</p> <h5 id="実際のやりかたとかは、"><a href="#%E5%AE%9F%E9%9A%9B%E3%81%AE%E3%82%84%E3%82%8A%E3%81%8B%E3%81%9F%E3%81%A8%E3%81%8B%E3%81%AF%E3%80%81">実際のやりかたとかは、</a></h5> <p>以下の記事に。<br /> ・<a target="_blank" rel="nofollow noopener" href="https://www.memory-lovers.blog/entry/2020/01/25/120000">Heroku+CloudflareなNuxtでSSRしてみる - くらげになりたい。</a></p> <h3 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h3> <p>いろいろ試してみたけど、Nuxt.jsを無料で公開するときは、</p> <ul> <li>SPAならNetlify <ul> <li>prerenderingで動的ページのSEOも対応</li> <li>カスタムドメインやSSLもNetlifyでOK</li> <li>定期実行はCloud Functionsで。</li> <li>ただし、定期実行は1アカウントにつき、3ジョブまで</li> </ul></li> <li>SSRならHeroku <ul> <li>SSRで動的ページのSEOも対応</li> <li>定期実行はHeroku Schedulerで</li> <li>Cloudflareを併用し、SSL対応</li> <li>無料枠は1アカウントにつき、1アプリが限界かも</li> </ul></li> </ul> <p>SSRの方は他に<a target="_blank" rel="nofollow noopener" href="https://cloud.google.com/run?hl=ja">Cloud Run</a>や<a target="_blank" rel="nofollow noopener" href="https://zeit.co/">ZEIT now</a>がある。<br /> Cloud Runは立ち上げがGAEより遅いときので後手だけど、<br /> ZEIT nowは気になってるので試してみたい(<em>´ω`</em>)</p> <p>以上!!</p> <h2 id="こんなのつくってます!!"><a href="#%E3%81%93%E3%82%93%E3%81%AA%E3%81%AE%E3%81%A4%E3%81%8F%E3%81%A3%E3%81%A6%E3%81%BE%E3%81%99%21%21">こんなのつくってます!!</a></h2> <p>積読用の読書管理アプリ 『積読ハウマッチ』をリリースしました!<br /> <a target="_blank" rel="nofollow noopener" href="https://tsundoku.site">積読ハウマッチ</a>は、Nuxt.js+Firebaseで開発してます!</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/572d4947-f40b-e4dc-1c9c-bc584cd2a66c.png" width="200"/></p> <p>もしよかったら、遊んでみてくださいヽ(=´▽`=)ノ</p> <p>要望・感想・アドバイスなどあれば、<br /> 公式アカウント(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/MemoryLoverz">@MemoryLoverz</a>)や開発者(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/kira_puka">@kira_puka</a>)まで!</p> <h3 id="へんあいマップもリリースしました!"><a href="#%E3%81%B8%E3%82%93%E3%81%82%E3%81%84%E3%83%9E%E3%83%83%E3%83%97%E3%82%82%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F%EF%BC%81">へんあいマップもリリースしました!</a></h3> <p>「偏愛マップ」を簡単に作れるWebアプリです!<br /> <a target="_blank" rel="nofollow noopener" href="https://hen-ai.net">へんあいマップ</a>も、Nuxt.js+Firebaseで開発してます!</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/63686f5c-390b-0b09-3f9a-0ce6676c3cce.png" width="600"/></p> <p>偏愛マップは人見知りや口下手な人にも優しいコミュニケーションツールで、<br /> 勉強会、懇親会、オフ会などの余興・アイスブレイクや自分のプロフィールにも!</p> <p>よかったら遊んでみてください(<em>´ω`</em>)</p> きらぷか@積読ハウマッチ/SSSAPIなど tag:crieit.net,2005:PublicArticle/15751 2020-03-08T22:46:20+09:00 2020-03-08T22:46:20+09:00 https://crieit.net/posts/GCE-Micro-Instance-with-burstable-CPU-running GCEのMicro Instance with burstable CPU runningに注意 <p>GCPのGoogle Compute EngineにはAlways Freeによる無料枠があるため、f1-microというインスタンスタイプであればサーバー自体は無料で運用することができる。</p> <p>ただし、あくまでもCloud Platformなので、実際にはサーバーを動作させるためのあれこれで費用がかかったりする。例えばネットワーク料金や、IPの料金など。もちろんこのあたりも無料枠があるので基本的にはだいたい無料で運用できる。かかるとしても数円程度。</p> <h2 id="料金が発生するパターン"><a href="#%E6%96%99%E9%87%91%E3%81%8C%E7%99%BA%E7%94%9F%E3%81%99%E3%82%8B%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3">料金が発生するパターン</a></h2> <p>しかし、色々試しているうちに費用が発生してしまうパターンが見つかった。料金表を見ていると「Micro Instance with burstable CPU running in Americas」ということで1,730円分も料金が発生していることに気づいた(無料クレジット期間のためまだ無料だが)。</p> <p><a href="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5e64f3f59a178.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5e64f3f59a178.png?mw=700" alt="" /></a></p> <p>これは何かというと、公式のマニュアルにも書かれているCPUバーストという機能。</p> <p><a target="_blank" rel="nofollow noopener" href="https://cloud.google.com/compute/docs/machine-types#cpu-バースト">CPU バースト</a></p> <p>CPUが足りなくなった時に、自動的にCPUを一時的に追加してくれるというもの。追加料金は通常は無いのだが、f1-microのようなマシンタイプの場合はこのように追加料金になるらしい。</p> <p>僕が前々から使っているこのCrieitなどで使っているf1-microサーバーではこの料金がかかったことはない。ただ、どうも使い方によってはこれが激しく使われる事があり、このように追加料金が発生してしまうっぽい。</p> <p>具体的にはこの記事のパターンで発生した。</p> <p><a href="https://crieit.net/posts/GCE-DB-GAE">GCEをDBサーバーにしてGAEでサービスを無料運用する</a></p> <p>単にDBサーバーとして利用していた、というだけなので、通常であればさほど料金が発生することはない。ただ、もしかしたら上記の構成だとちょこちょこ何かしらのアクセスや接続が発生してしまい、負荷につながってしまうのかもしれない。詳しいことは全くわからない。何にしろ、f1-microの無料枠は時間で決まっているので、このバーストにより時間が無料枠分を超えてしまう。</p> <h2 id="対処方法"><a href="#%E5%AF%BE%E5%87%A6%E6%96%B9%E6%B3%95">対処方法</a></h2> <p>GCPを利用し始めて1年間は無料クレジットが付いているため、基本的に問題になることは無いだろう。ちょこちょこ料金明細を見ておいて、おかしかったらその利用方法では費用が発生してしまう可能性があるため、構成を見直せばいい。それでどうしても費用とパフォーマンスがあわないようであればその間に他のサーバーを検討すればいい。</p> <p>すでに無料クレジットの期間が終わってしまっている場合は注意が必要。無料だと思っていてこの料金がかかってしまうとちょっとびっくりする。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/15667 2020-01-07T23:15:57+09:00 2020-12-25T17:23:36+09:00 https://crieit.net/posts/GCE-DB-GAE GCEをDBサーバーにしてGAEでサービスを無料運用する(を構築したけど費用がかかった) <p>GCPでリリースしたサービスが1年経ち無料クレジットの期限をむかえそうになりました。Cloud SQLを使ってデプロイしたためその後は有料になってしまうのですが、誰も使っていないサービスのためなんとか無料で運用できる方法は無いかと考えました。ちなみに下記のような構成です。</p> <ul> <li>Node.js</li> <li>MySQL5.7</li> </ul> <p>しかしサービスの性質上ちょっとデータベースのデータも多めで、HerokuのMySQLだと無料プランでは無理なのかな…という気がしました。そうするとMySQLを使えて無料で運用できるサービスが他にはありません。</p> <p>そこでふと、アプリケーション・サーバーはGoogle App Engine、データベースサーバーをGoogle Compute Engineで運用してみたらどうだろう、と思い立ちやってみました。</p> <p><a href="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5e14888763bb5.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5e14888763bb5.png?mw=700" alt="" /></a></p> <h2 id="後日談の追記"><a href="#%E5%BE%8C%E6%97%A5%E8%AB%87%E3%81%AE%E8%BF%BD%E8%A8%98">後日談の追記</a></h2> <p>こういうのが出るみたいなので無料は無理なのかもしれません。Micro instance with burstable CPU running。</p> <p><a href="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5e440681eb425.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5e440681eb425.png?mw=700" alt="" /></a></p> <p>普通にサーバーとして使ってる時は出ないのでGAEかネットワークから必要以上に接続が来てしまうのかもしれませんね…。(もしくは最近新しく作ったGCEだと出るようになったとかだったり?)</p> <p>追記)<br /> GCEにWeb+DB全部入れにしたら費用がかからなくなったのでやはりこの構成だと費用がかかるみたいです。</p> <h2 id="GAEからGCEにローカル接続する"><a href="#GAE%E3%81%8B%E3%82%89GCE%E3%81%AB%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E6%8E%A5%E7%B6%9A%E3%81%99%E3%82%8B">GAEからGCEにローカル接続する</a></h2> <p>結局のところ、今回の話ではこれが一番重要です。そもそもApp EngineからCompute Engineにローカル接続できるのか、と。</p> <p>これは実はこの記事を書いている2020/1時点では日本語マニュアルではまだβ版という表記が残っている、リリースされたばかりの「サーバーレスVPCアクセス」という機能を使うことによって可能です。</p> <p><a target="_blank" rel="nofollow noopener" href="https://cloud.google.com/appengine/docs/standard/nodejs/connecting-vpc">Connecting to a VPC network  |  App Engine standard environment for Node.js docs |  Google Cloud</a></p> <p>Compute EngineはVPCネットワーク内に位置しているのですが、App Engineはこれとは別のネットワークに存在しています。そのため、このサーバーレスVPCアクセスという機能を使うことで、下記にも書かれていますがApp Engineのスタンダード環境やCloud FunctionsからCompute EngineやCloud SQLに内部IPでアクセスできるようになります。</p> <p><a target="_blank" rel="nofollow noopener" href="https://cloud.google.com/vpc/docs/configure-serverless-vpc-access?hl=ja">Serverless VPC Access の構成  |  VPC |  Google Cloud</a></p> <p>日本語だとデプロイ時にbetaをつけろと書かれていますが恐らく今は不要だと思います。</p> <h3 id="サーバーレスVPCアクセスの設定"><a href="#%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%83%AC%E3%82%B9VPC%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%AE%E8%A8%AD%E5%AE%9A">サーバーレスVPCアクセスの設定</a></h3> <p>サーバーレスVPCアクセスのページを開くとコネクタを作成というリンクがあるのでクリックします。</p> <p><a href="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5e148b1948283.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5e148b1948283.png?mw=700" alt="" /></a></p> <p>作成画面に必要な項目を入力して作成します。</p> <p><a href="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5e148b657d6f0.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5e148b657d6f0.png?mw=700" alt="" /></a></p> <p>注意が必要な点としてまだリリースされたばかりのためリージョンが少ないです。最初にApp Engineを登録してしまうと、同じリージョンがない…! みたいなことになるので気をつけましょう。us-central1であればGAEのus-centralと合います。</p> <p>IP範囲は補足に書かれている感じで大丈夫です。要するに、既存のVPCネットワークのIPとかぶっていないIP範囲であれば大丈夫です。</p> <h3 id="App Engineの設定"><a href="#App+Engine%E3%81%AE%E8%A8%AD%E5%AE%9A">App Engineの設定</a></h3> <p>App Engineのリージョンは先程作成したコネクタのリージョンに合わせて作成しましょう。多分作ってしまった後は変更できないのではないかと思います……。ただ、ちょっとApp Engineを作り直せない関係で色々試すことができたわけではないので、リージョンが違ったらダメかどうかは詳しく検証できていません。</p> <p>あとはapp.yamlに、このコネクタに接続するための設定を追記します。</p> <pre><code class="yaml">vpc_access_connector: name: "projects/PROJECT_ID/locations/REGION/connectors/CONNECTOR_NAME" </code></pre> <p>REGIONとCONNECTOR_NAMEはコネクタのものです。これでデプロイすれば接続され、Compute Engineの内部IPと接続することができるようになります。</p> <h3 id="Compute Engineの設定"><a href="#Compute+Engine%E3%81%AE%E8%A8%AD%E5%AE%9A">Compute Engineの設定</a></h3> <p>デフォルトだとCompute Engineの内部IPはエフェメラルになっているため、時々勝手に変わってしまいます。</p> <p><a href="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5e148d61aba91.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5e148d61aba91.png?mw=700" alt="" /></a></p> <p>静的内部IPアドレスを予約して固定にしておきましょう。外部IPは不要です。固定外部IPを使っていた場合は、ただそれを外すだけだと使われない外部IPになってしまい、費用が発生してしまいますのでIPを解放しておきましょう。</p> <p>あとはMySQLをインストールして設定しましょう。どこからもアクセスできないのでMySQLユーザーは <code>ユーザー名@'%'</code> とかでいいのではないかと思います(違ったら教えていただけると助かります)。</p> <p>問題なければこれで接続できます(のはず……)</p> <h2 id="諸々設定"><a href="#%E8%AB%B8%E3%80%85%E8%A8%AD%E5%AE%9A">諸々設定</a></h2> <p>とはいえGAEは無料枠があるというだけでそれ以降は有料となってしまいます。こにさんのブログを参考にしてなるべくオーバーしないようにすると良いでしょう。</p> <p><a target="_blank" rel="nofollow noopener" href="https://koni.hateblo.jp/entry/2016/01/06/130613">Google App Engineを無料で運用する方法(2018年版) - koni blog</a></p> <p>スタンダード環境にてAutoScalingのF1というプランです。スケールしないプランもありますがそちらは無料枠が少なく毎月有料になってしまいます。</p> <p>どちらにしろすごくアクセスのあるサイトだと有料になってしまうと思いますので今回のようにもう誰も使っていないサービスを残しておくとか、作ったばかりのサービスで試す場合とかにこの構成だと良いのではないかと思います。</p> <p>あとCloud SQLのように便利な機能はないので適宜バックアップを取っておきましょう。</p> <p><a href="https://crieit.net/posts/Google-Cloud-Storage-DB">Google Cloud Storage無料DBバックアップ</a></p> <p>また、DBサーバーはメモリが不足してしょっちゅう止まる可能性もありますので、swapの設定もしておいた方が良いでしょう。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/15662 2020-01-03T22:24:35+09:00 2020-01-03T22:24:35+09:00 https://crieit.net/posts/2020-GCE-IP 2020年からはGCEの外部IPが有料となりますが無料枠もあります <p>GCPのクラウドサーバーであるGoogle Compute EngineはAlways Freeという無料枠によりf1-microは無料で利用ができます(細かい条件はあります)。しかし2019年から囁かれはじめたとおり、2020年からは外部IPが有料となりました。</p> <p>新年あけましておめでとうございますしてから、僕にも請求アラートが飛んでくるようになりました。見てみるとたしかに外部IPの費用分が追加されていました。(External IPの箇所)</p> <p><a href="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5e0f3ed8db3f6.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5e0f3ed8db3f6.png?mw=700" alt="" /></a></p> <p>ただし無料枠の割引もあるようです。</p> <p><a href="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5e0f3f4100fee.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5e0f3f4100fee.png?mw=700" alt="" /></a></p> <p>詳しくは下記に書かれていました。</p> <p><a target="_blank" rel="nofollow noopener" href="https://cloud.google.com/free/docs/gcp-free-tier?hl=ja#always-free-usage-limits">Google Cloud の無料枠  |  Google Cloud Platform の無料枠 |  Google Cloud</a></p> <blockquote> <p>注: Google Cloud では、2020 年 1 月 1 日から VM インスタンスの外部 IP アドレスの使用に料金がかかります。 ただし、Google Cloud の無料枠では当月内の合計時間数と同等の時間数を使い切るまで、使用中の外部 IP アドレスを無料でご利用いただけます。使用中の外部 IP アドレスの Google Cloud 無料枠は、f1-micro インスタンスだけでなく、すべてのインスタンス タイプに適用されます。</p> </blockquote> <p>無料枠はf1-microだけだと思うのでちょっとよく意味はわからないのですが、とりあえずf1-microであればずっと無料で行けるのではないかと思います。(実際に1ヶ月丸々試せてはいないので今後も引き続き見ていきますが)</p> <p>とはいえ課金+割引という方式のようですので、無料枠無視の請求アラートにしていた場合は、設定によってはアラートが飛んでくるようになっています。煩わしいようであれば請求アラートの設定を調整しておいた方が良さそうです。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/15553 2019-11-17T14:30:30+09:00 2019-11-17T14:30:30+09:00 https://crieit.net/posts/GCE GCEでインスタンスを作るときにやることリスト <p>今更ながらGoogle Compute Engine(GCE)を使ってみたいなと思い、<br /> インスタンス作るときにやった手順をまとめてみた。</p> <p>ほぼ、以下の2つの記事を見てやった手順をまとめただけの備忘録。<br /> ・ <a target="_blank" rel="nofollow noopener" href="https://qiita.com/ndxbn/items/7ef0a96e409a5b5837bd#ip%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%82%92%E5%9B%BA%E5%AE%9A%E3%81%97%E3%81%A6%E3%81%8A%E3%81%8F">GCE の無料枠のサーバを立るときに、初見でハマりそうなところ - Qiita</a><br /> ・ <a target="_blank" rel="nofollow noopener" href="https://qiita.com/riku-shiru/items/a870edd9dc0b132e092c#80443%E3%83%9D%E3%83%BC%E3%83%88%E3%82%92%E8%A7%A3%E6%94%BE%E3%81%99%E3%82%8B">GCPで永久無料枠を利用してサービスを立ち上げたときにしたことの備忘録 - Qiita</a></p> <h3 id="1. インスタンス作成"><a href="#1.+%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E4%BD%9C%E6%88%90">1. インスタンス作成</a></h3> <p>imageはUbuntu 18.04(Minimal)を選択</p> <ul> <li>f1-microにする</li> <li>80, 433ポートを開放する <ul> <li>「HTTPトラフィックを許可する」にチェック</li> <li>「HTTPSトラフィックを許可する」にチェック</li> </ul></li> <li>IPを固定にする <ul> <li>「ネットワーキング」>「ネットワークインターフェース」>「外部IP」</li> <li><strong>「プライマリ内部IP」とは違うので注意</strong></li> </ul></li> </ul> <h3 id="2. SSHの設定"><a href="#2.+SSH%E3%81%AE%E8%A8%AD%E5%AE%9A">2. SSHの設定</a></h3> <h4 id="2-1. ポート変更"><a href="#2-1.+%E3%83%9D%E3%83%BC%E3%83%88%E5%A4%89%E6%9B%B4">2-1. ポート変更</a></h4> <ul> <li>メニューの「VPCネットワーク」>「ファイアウォールルール」から</li> <li>「ファイアウォール ルールの作成」を押して作成 <ul> <li>ターゲットタグ: original-allow-ssh</li> <li>ソースIPの範囲: 0.0.0.0/0</li> <li>プロトコルとポート: tcp 40022</li> </ul></li> <li>VMの「ネットワークタグ」に「ターゲットタグ」をつける</li> <li>「VMインスタンス」にある該当のVMの「接続」>「SSH」を押してブラウザでログイン</li> </ul> <pre><code class="shell"># apt updateしないとvimをインストールできない $ sudo apt update $ sudo apt install -y vim $ sudo vim /etc/ssh/sshd_config $ sudo systemctl restart sshd </code></pre> <pre><code class="diff"> #Port 22 + Port XXXX (XXXX は さっき開けたポート番号) #AddressFamily any #ListenAddress 0.0.0.0 #ListenAddress :: </code></pre> <p>sshdを再起動したら、<strong>編集したブラウザは閉じずに</strong>、<br /> 「接続」>「ブラウザからカスタムポートで SSH を開く」から<br /> 変更したポートで接続してみて、つながるかどうかを確認</p> <p>うまくできたらポートを閉じる</p> <ul> <li>「ファイアウォールルール」に移動</li> <li>「ファイアウォール ルールの作成」を押して作成 <ul> <li>ターゲットタグ: disallow-ssh22</li> <li>一致したときのアクション: 拒否</li> <li>ソースIPの範囲: 0.0.0.0/0</li> <li>プロトコルとポート: tcp 22</li> </ul></li> <li>VMの「ネットワークタグ」に「ターゲットタグ」をつける</li> </ul> <h4 id="2-2. 公開鍵の認証"><a href="#2-2.+%E5%85%AC%E9%96%8B%E9%8D%B5%E3%81%AE%E8%AA%8D%E8%A8%BC">2-2. 公開鍵の認証</a></h4> <pre><code class="shell"># 鍵を生成。アカウント名はmemorylovers $ ssh-keygen -t rsa -f ~/.ssh/gcp_key -C memorylovers $ chmod 400 ~/.ssh/gcp_key # 公開鍵をコピー $ cat ~/.ssh/gcp_key.pub | pbcopy </code></pre> <ul> <li>メニューの「VMインスタンス」から該当のVMを選択し、編集画面へ</li> <li>SSHキーに貼り付けて、保存</li> </ul> <p>接続確認をしてみる</p> <pre><code class="shell">$ ssh memorylovers@<IPアドレス> -p <指定したポート> -i ~/.ssh/gcp_key </code></pre> <h4 id="2-3. SSHの設定を変更"><a href="#2-3.+SSH%E3%81%AE%E8%A8%AD%E5%AE%9A%E3%82%92%E5%A4%89%E6%9B%B4">2-3. SSHの設定を変更</a></h4> <p>ポート番号以外について、確認・設定していく</p> <pre><code class="diff"> # プロトコルを2にする + Protocol 2 # rootログインを無効にする #PermitRootLogin prohibit-password + PermitRootLogin no # パスワード認証を無効にする PasswordAuthentication no ChallengeResponseAuthentication no # 認証の試行回数を制限する #MaxAuthTries 6 + MaxAuthTries 5 </code></pre> <p>設定が終わったらsshdを再起動して設定を反映</p> <pre><code class="shell">$ sudo systemctl restart sshd </code></pre> <p>以上!! これでインスタンスが作成できた!</p> <h2 id="こんなのつくってます!!"><a href="#%E3%81%93%E3%82%93%E3%81%AA%E3%81%AE%E3%81%A4%E3%81%8F%E3%81%A3%E3%81%A6%E3%81%BE%E3%81%99%21%21">こんなのつくってます!!</a></h2> <p>積読用の読書管理アプリ 『積読ハウマッチ』をリリースしました!<br /> <a target="_blank" rel="nofollow noopener" href="https://tsundoku.site">積読ハウマッチ</a>は、Nuxt.js+Firebaseで開発してます!</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/572d4947-f40b-e4dc-1c9c-bc584cd2a66c.png" width="200"/></p> <p>もしよかったら、遊んでみてくださいヽ(=´▽`=)ノ</p> <p>要望・感想・アドバイスなどあれば、<br /> 公式アカウント(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/MemoryLoverz">@MemoryLoverz</a>)や開発者(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/kira_puka">@kira_puka</a>)まで♪</p> <h1 id="参考にしたサイト"><a href="#%E5%8F%82%E8%80%83%E3%81%AB%E3%81%97%E3%81%9F%E3%82%B5%E3%82%A4%E3%83%88">参考にしたサイト</a></h1> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/ndxbn/items/7ef0a96e409a5b5837bd#ip%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%82%92%E5%9B%BA%E5%AE%9A%E3%81%97%E3%81%A6%E3%81%8A%E3%81%8F">GCE の無料枠のサーバを立るときに、初見でハマりそうなところ - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/riku-shiru/items/a870edd9dc0b132e092c#80443%E3%83%9D%E3%83%BC%E3%83%88%E3%82%92%E8%A7%A3%E6%94%BE%E3%81%99%E3%82%8B">GCPで永久無料枠を利用してサービスを立ち上げたときにしたことの備忘録 - Qiita</a></li> </ul> きらぷか@積読ハウマッチ/SSSAPIなど tag:crieit.net,2005:PublicArticle/15546 2019-11-14T08:49:36+09:00 2019-11-14T08:49:36+09:00 https://crieit.net/posts/Google-Compute-Engine-gcloud Google Compute Engine利用時に使うgcloudコマンド備忘録 <p>Google Compute Engineを使っているとサーバーと接続するために色々なgcloudコマンドを利用する必要がある。普段はシェルの実行履歴から呼び出して使っているけど、何かのひょうしにPCが壊れて履歴がなくなってしまったら困るし、結構一から使い方を探すと見つからなかったりするのでとりあえずまとめておく。</p> <h2 id="SSH接続"><a href="#SSH%E6%8E%A5%E7%B6%9A">SSH接続</a></h2> <pre><code>gcloud compute --project "my-project-id" ssh --zone "us-east1-b" "instance-1" </code></pre> <h2 id="ポートフォワーディング"><a href="#%E3%83%9D%E3%83%BC%E3%83%88%E3%83%95%E3%82%A9%E3%83%AF%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0">ポートフォワーディング</a></h2> <p>ローカルPCでサーバーのデータベースと接続するときとか</p> <pre><code>gcloud compute --project "my-project-id" ssh --zone "us-east1-b" "instance-1" -- -L 13306:localhost:3306 </code></pre> <h2 id="SCPで送信"><a href="#SCP%E3%81%A7%E9%80%81%E4%BF%A1">SCPで送信</a></h2> <p>SCPでファイルを送ったり受信したりする時。ファイルとフォルダによってちょっと違う。</p> <h3 id="ファイルを送信"><a href="#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E9%80%81%E4%BF%A1">ファイルを送信</a></h3> <pre><code>gcloud compute scp --project "my-project-id" --zone "us-central1-f" instance-1:/home/dala00/profile.sql.gz . </code></pre> <h3 id="フォルダを送信"><a href="#%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80%E3%82%92%E9%80%81%E4%BF%A1">フォルダを送信</a></h3> <pre><code>gcloud compute scp --project "my-project-id" --zone "us-west1-b" --recurse instance-1:/home/dala00/questions localdir </code></pre> <h2 id="コマンドを実行する"><a href="#%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B">コマンドを実行する</a></h2> <pre><code>gcloud compute --project "my-project-id" ssh --zone "us-west1-b" dala00@"instance-1" --command 'touch bbb.txt;rm aaa.txt' </code></pre> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/15427 2019-09-26T22:08:54+09:00 2019-09-26T22:08:54+09:00 https://crieit.net/posts/React-PWA-Rails-GraphQL-RPG React PWA + Rails GraphQLで作ったポモドーロRPGに使った技術やその選定理由を書いてみた <p>先日、『<a target="_blank" rel="nofollow noopener" href="https://www.g-g-g-g.games">g4</a>』というポモドーロ+RPGなサービスをリリースしました。</p> <p>そのサービスで使った技術について聞かれることがあったので残しておきます。</p> <h1 id="どんなサービス?"><a href="#%E3%81%A9%E3%82%93%E3%81%AA%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%3F">どんなサービス?</a></h1> <p>ポモドーロ・タイマーを使い25分間集中すると経験値をもらえ、その経験値でレベルが上がる。<br /> って言う感じのやつです。</p> <p><a target="_blank" rel="nofollow noopener" href="https://www.g-g-g-g.games">https://www.g-g-g-g.games</a></p> <p><a target="_blank" rel="nofollow noopener" href="https://www.g-g-g-g.games"><a href="https://crieit.now.sh/upload_images/4857e38ac110f7f2ccb9a3a6c9851f425d8c46a290533.jpeg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/4857e38ac110f7f2ccb9a3a6c9851f425d8c46a290533.jpeg?mw=700" alt="https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_51402_6c1fef60-9f24-2233-821b-1b4b16575e21.jpeg" /></a></a></p> <h2 id="こんな特徴があります。"><a href="#%E3%81%93%E3%82%93%E3%81%AA%E7%89%B9%E5%BE%B4%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82">こんな特徴があります。</a></h2> <ul> <li>ポモドーロ・タイマーやRPG的なUIはリッチで動きがある</li> <li>現在のステータスをOGP画像にしてシェアできる</li> <li>上昇する能力値や覚えるスキルは登録した文章を解析して決まる</li> </ul> <h1 id="構成はこんな感じ"><a href="#%E6%A7%8B%E6%88%90%E3%81%AF%E3%81%93%E3%82%93%E3%81%AA%E6%84%9F%E3%81%98">構成はこんな感じ</a></h1> <p><a href="https://crieit.now.sh/upload_images/a91960cfcbabfe4677662c7e3a35b9225d8c468610acb.jpeg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/a91960cfcbabfe4677662c7e3a35b9225d8c468610acb.jpeg?mw=700" alt="https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_51402_1f7797cd-59e5-b556-2afe-b0a964acd0ac.jpeg" /></a></p> <h2 id="フロントエンドの選定理由"><a href="#%E3%83%95%E3%83%AD%E3%83%B3%E3%83%88%E3%82%A8%E3%83%B3%E3%83%89%E3%81%AE%E9%81%B8%E5%AE%9A%E7%90%86%E7%94%B1">フロントエンドの選定理由</a></h2> <p>フロントエンドはSSRしたReactアプリをfly.ioにおいています</p> <h3 id="[React]"><a href="#%5BReact%5D">[React]</a></h3> <p>自分は過去に仕事でNuxt.jsや生Vue.jsを使ったことがあり、個人ではExpoやNext.jsでReactにも触っていました。</p> <p>今回Reactを選択した理由は以下です。</p> <ul> <li>型が欲しかった。Typescriptを使いたかった</li> <li>Reactのほうが書いていて楽しい(個人の感想です) <ul> <li>React Hooksめっちゃいい</li> </ul></li> <li>Apolloを使うならVueよりReactのほうが色々揃っている</li> </ul> <h3>[<a target="_blank" rel="nofollow noopener" href="https://fly.io">fly.io</a>]</h3> <p>SSRするためにNode.jsをホスティングするやつが欲しかったので選定。<br /> <a target="_blank" rel="nofollow noopener" href="https://mizchi.hatenablog.com/entry/2019/02/21/235403">mizchiさんのブログ</a>で知り、面白そうだなと思ったのがきっかけ。<br /> べつにfirebase hostingでもよかったですが、以下が決め手</p> <ul> <li>firebase hosting同様初期導入費用がほぼ0</li> <li>CDN</li> <li>キャッシュコントロール</li> <li>svgを使ったOGP画像の生成ができる</li> </ul> <p>特に、</p> <blockquote> <p>svgを使ったOGP画像の生成ができる</p> </blockquote> <p>に有用性を感じて選定したんですが、現時点ではカスタムフォントと日本語への対応が十分でなく、別途Cloud Runを使うことになってしまっています(後述)<br /> (サポートに聞いたらリポジトリ教えてもらったので(OSS)対応できるようなら自分で対応してなげたいなぁ)</p> <h5 id="キャッシュコントロールもよい"><a href="#%E3%82%AD%E3%83%A3%E3%83%83%E3%82%B7%E3%83%A5%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%82%82%E3%82%88%E3%81%84">キャッシュコントロールもよい</a></h5> <p>キャッシュの操作も面白くて、<br /> g4の公開用ページではAPIからもらった結果をキャッシュして、キャッシュがあればそれをそのまま返すということをしています。</p> <p>これによってAPIサーバーへの負荷はかなり低くなってると思います。<br /> APIサーバー側からは、データ更新時にfly.ioのキャッシュを削除する操作をしていて、データが更新されるまではfly.ioはキャッシュを使い続けてます。</p> <p>この辺のAPIが普通に使いやすくて簡単にかけるのでめっちゃ良きです。</p> <h5 id="fly.io良いよ"><a href="#fly.io%E8%89%AF%E3%81%84%E3%82%88">fly.io良いよ</a></h5> <p>fly.io自体ははデプロイも早いし、導入コストも安いので<a target="_blank" rel="nofollow noopener" href="https://zeit.co">now</a>とかと並べて、手軽にNode.jsをホスティングするための選択肢にしてもいいんじゃないかなって思います。</p> <h3 id="Next.jsを選ばなかった理由"><a href="#Next.js%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%8B%E3%81%A3%E3%81%9F%E7%90%86%E7%94%B1">Next.jsを選ばなかった理由</a></h3> <p>SSRする予定ではありましたが、OGPだけ生成できればいいなというレベルだったので、通常のReactアプリで作りました。<br /> なるべく継続開発するため、アップデートの手間と依存を減らしたかったのも少しある</p> <h3 id="[PWA]を選定した理由"><a href="#%5BPWA%5D%E3%82%92%E9%81%B8%E5%AE%9A%E3%81%97%E3%81%9F%E7%90%86%E7%94%B1">[PWA]を選定した理由</a></h3> <p>最初は、<a target="_blank" rel="nofollow noopener" href="https://expo.io">Expo</a>で作ろうかと思っていました。</p> <p>もともとSPAでアプリっぽいUIを作る仕事を受けたときに、Nuxt.js + Firebaseで作り、マルチブラウザ対応が辛いと思った経験がありました。</p> <p>RNならその辺いい感じに作れるかもと思って<a target="_blank" rel="nofollow noopener" href="https://shwld.net/seicho-release/">みんなの成長</a> というアプリでExpoを試しみて、使い勝手が良い事までは確認してました。</p> <p>ただ今回はモバイルより、デスクトップアプリのほうが欲しいということに気づき、<br /> Electronで作りやすかったり、PWAならそのままインストールもできちゃうのでWebでいいかなって思いPWAにしました。</p> <p>なのでマルチブラウザ辛いは解決してないです。<br /> ここは個人開発なので修行と割り切って本業に生かしていきます。<br /> Safari対応が結構めんどいけど、ユーザー多くて無視できない...</p> <p>マルチブラウザと言っても、現状Chrome、Safari以外はほぼ無視してまっす。</p> <h3>[<a target="_blank" rel="nofollow noopener" href="https://www.apollographql.com">Apollo Client (react-apollo)</a>]</h3> <p>これもSPAでアプリっぽいUIを作る仕事で、Nuxt.js + Firebaseで作ったときに、Firebaseのデータベース(このときはrealtime database使ってた)をフロントに反映するのが辛くて、同じようにREST APIも辛いだろうなと思って、GraphQLに手をだしたのがきっかけでした。</p> <p>GraphQLだけでもすごく良いのですが、Apollo Clientがいいのはキャッシュコントールで、<br /> クエリ毎にキャッシュを優先するかサーバーを優先するかを選択できます。</p> <p>また、キャッシュがあれば再取得しないなどを簡単に書けたり、とにかくこれはSPAのベストプラクティスだなって感じの実装をシンプルに書けます。</p> <p>Mutationするとキャッシュが書き換わったりするのもめっちゃ良き</p> <p>正直この辺のこと考えながらSPA実装するのってかなり大変じゃない?ってか大変だった<br /> アプリライクなUIのSPAならApollo Client使おうぜ!</p> <p>こいつのおかげでこれまたAPIサーバーの負荷はまあまあ抑えられてそうです。</p> <h2 id="[Firebase Auth, Storage]について"><a href="#%5BFirebase+Auth%2C+Storage%5D%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">[Firebase Auth, Storage]について</a></h2> <p>バックエンドはRailsですが、APIサーバー作るのに正直Deviseとか使いたくないです(完)</p> <p>Twitter連携やら諸々簡単なので選ばない理由がない。<br /> Auth0は選択肢に入るけど今回GCPなのでGoogleでまとめられるし、そこまで込み入った認証必要ないしでこれにしました。</p> <p>Storageは別に何でもよかったですが、Firebase Authの認証ユーザー単位での権限指定が楽なので使い勝手は良いです。</p> <h2 id="デザインについて"><a href="#%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">デザインについて</a></h2> <p>g4のデザインはレスポンシブのヘルパーとして<a target="_blank" rel="nofollow noopener" href="https://github.com/twbs/bootstrap/blob/master/dist/css/bootstrap-grid.css">bootstrap-grid</a>だけ使わせてもらってます。<br /> めっちゃ便利なのでおすすめ。</p> <p>それ以外はcss全部自分で書いてます。</p> <p>コンポーネントファーストで作成しており、Atomic Designの粒度で、<a target="_blank" rel="nofollow noopener" href="https://storybook.js.org">Storybook</a>作ってコンポーネントを作ってる感じです。<br /> Storybookは割とぶっ壊れやすかったり、他のビルド設定と競合とか重複したり、辛みもありますが、<a target="_blank" rel="nofollow noopener" href="https://storybook.js.org/docs/testing/structural-testing/">storyshots</a>によるスナップショットの差分確認ができるのと、テストの安心感があるので、無いと無いで不安ではあります。</p> <h2 id="バックエンドの選定理由"><a href="#%E3%83%90%E3%83%83%E3%82%AF%E3%82%A8%E3%83%B3%E3%83%89%E3%81%AE%E9%81%B8%E5%AE%9A%E7%90%86%E7%94%B1">バックエンドの選定理由</a></h2> <h3>[<a target="_blank" rel="nofollow noopener" href="https://graphql-ruby.org">graphql-ruby</a> & Ruby on Rails]</h3> <p>Apollo Clientの項で書きましたが、GraphQLを使うことは決まっていました。<br /> GraphQLをマネージドでホスティングしてくれるやつを探したりしたんですが、普段Railsエンジニアなので慣れてるからテストとかも書きやすいしRailsでいっかで、graphql-rubyにしました。</p> <p>Railsにするとランニングコストは割とかかるんですが、今回は個人開発のメインに据えて長く継続開発したいを目的にしてたので、<br /> 稼働してないものにお金払うみたいなことにならない想定(自分が使い続ける)で、コストかける覚悟はしました。</p> <p>graphql-rubyは仕事でも使ってるので、今後も押していきたい存在。</p> <h3 id="[GCP/App Engine]"><a href="#%5BGCP%2FApp+Engine%5D">[GCP/App Engine]</a></h3> <p>App Engineについては<a target="_blank" rel="nofollow noopener" href="https://qiita.com/shwld/items/e86ee3f642c7857dd56e">こちらの記事</a>で書きました。</p> <p>要約するとHerokuでも良かったけど、使ってみたかったのでGCPにした。です。</p> <h2 id="[GCP/Natural Language API]"><a href="#%5BGCP%2FNatural+Language+API%5D">[GCP/Natural Language API]</a></h2> <p>便利。Azureとかにもありますが、今回はGoogle統一で行きました。くらいの選定理由</p> <h2 id="[GCP/Cloud Run]について"><a href="#%5BGCP%2FCloud+Run%5D%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">[GCP/Cloud Run]について</a></h2> <p>Cloud Runは今回使う予定は全くありませんでした。</p> <p>今利用している理由としては、</p> <ul> <li>fly.ioでOGPを生成できるとふんでいたができなかった。</li> <li>とりあえず手っ取り早くカスタムしたDockerimageでfry.ioをあまりお金をかけずに使えるとこはないか。</li> </ul> <p>からの、Cloud Run。</p> <p>中身は日本語とフォントをインストールした普通のNodeイメージに<br /> fly.ioのサーバーを単純に乗っけて起動しているだけです。(プレビルドして実行したいがやり方が分からずdevサーバー起動しているのでなんとかしたい。誰かやり方知りませんか。)</p> <p>なので、いずれはfly.ioだけでできるようして、Cloud Runをやめたいです。</p> <h4 id="Cloud Run超便利"><a href="#Cloud+Run%E8%B6%85%E4%BE%BF%E5%88%A9">Cloud Run超便利</a></h4> <p>そんな理由で使い始めましたが、驚くくらい簡単かつ手軽にカスタムDockerイメージが使えるので、Cloud Runめっちゃ便利です。<br /> 今後活用していきたい。</p> <h2 id="おわりに"><a href="#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB">おわりに</a></h2> <p>割と構成的にはガチよりになりました。<br /> 自分の技術力総動員してる感じなのでテンション上がってめっちゃ楽しい!</p> <p>g4の運用を支える技術についても今後書いていきたいです。</p> <p>みんなでレベル上げしましょう!</p> <p><a target="_blank" rel="nofollow noopener" href="https://www.g-g-g-g.games">https://www.g-g-g-g.games</a></p> <p><a target="_blank" rel="nofollow noopener" href="https://www.g-g-g-g.games"><a href="https://crieit.now.sh/upload_images/4857e38ac110f7f2ccb9a3a6c9851f425d8c46a290533.jpeg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/4857e38ac110f7f2ccb9a3a6c9851f425d8c46a290533.jpeg?mw=700" alt="https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_51402_6c1fef60-9f24-2233-821b-1b4b16575e21.jpeg" /></a></a></p> shwld tag:crieit.net,2005:PublicArticle/15421 2019-09-24T19:17:59+09:00 2019-09-24T19:17:59+09:00 https://crieit.net/posts/Firestore-gcloud Firestoreのデータをgcloudを使ってバックアップ&別のプロジェクトへインポートしてみる <p>Firestoreのデータをガリガリ見ていきたいなと思っていたら、<br /> 別のプロジェクトに移行できそうだったので、いろいろ調べたときの備忘録。</p> <p>分析目的だけど、BigQueryは1000カラム制約で使えなかったので代替案...<br /> 別プロジェクトなら無料枠でいろいろできそう。</p> <h3 id="注意"><a href="#%E6%B3%A8%E6%84%8F">注意</a></h3> <p>Firestoreのエクスポート/インポートについて、いくつか注意。</p> <ol> <li>Firestoreのエクスポート/インポートは<strong>Blazeプラン</strong>が必要(無料枠では不可)</li> <li>ドキュメントの読み取りと書き込み時にCloud Firestoreの料金が課金される</li> </ol> <p>さらに、</p> <blockquote> <p>エクスポート / インポート オペレーションのコストは、<strong>費用制限の対象にはなりません</strong>。<br /> オペレーションが完了するまで、エクスポート/インポートでGCPの<strong>予算アラートはトリガーされません</strong>。</p> </blockquote> <p>とのことなので、ご利用は計画的に..</p> <hr /> <h3 id="1. gcloudのインストール"><a href="#1.+gcloud%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">1. gcloudのインストール</a></h3> <h4 id="インストール"><a href="#%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">インストール</a></h4> <pre><code class="console">$ brew cask install google-cloud-sdk </code></pre> <h4 id=".bashrcなどに以下を追記"><a href="#.bashrc%E3%81%AA%E3%81%A9%E3%81%AB%E4%BB%A5%E4%B8%8B%E3%82%92%E8%BF%BD%E8%A8%98">.bashrcなどに以下を追記</a></h4> <pre><code class="bash">source '/usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/path.bash.inc' source '/usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/completion.bash.inc' </code></pre> <h4 id="gcloudの初期化"><a href="#gcloud%E3%81%AE%E5%88%9D%E6%9C%9F%E5%8C%96">gcloudの初期化</a></h4> <pre><code class="console"># 初期設定の実行 $ gcloud init # このあと、ログイン画面が出てきて認証する # コンポーネントのアップデート $ gcloud components update # 現在のプロジェクトの確認 $ gcloud info | grep project </code></pre> <h3 id="2. FirestoreのデータをExportする"><a href="#2.+Firestore%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92Export%E3%81%99%E3%82%8B">2. FirestoreのデータをExportする</a></h3> <p><code>firestore export</code>を使うと、データのバックアップが作成できるらしい。<br /> バックアップデータはGCPのStorage上に作成されるので、<br /> あらかじめ、Storageを作成しておく必要がある。</p> <pre><code class="console"># 現在のプロジェクトの確認 $ gcloud info | grep project # 全体のエクスポート $ gcloud beta firestore export gs://[BUCKET_NAME] # コレクションを指定して、一部だけをエクスポート $ gcloud beta firestore export gs://[BUCKET_NAME] --collection-ids=[COLLECTION_ID_1],[COLLECTION_ID_2] # 実行状況の確認 $ gcloud beta firestore operations list </code></pre> <p>データ量が多いと、コマンドが途中で終了するので、<br /> 完了したかどうかは<code>operations list</code>を実行して確認する必要がある。</p> <p>参考: <a target="_blank" rel="nofollow noopener" href="https://firebase.google.com/docs/firestore/manage-data/export-import?hl=ja">データのエクスポートとインポート  |  Firebase</a></p> <h3 id="3. プロジェクトを変更する"><a href="#3.+%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%92%E5%A4%89%E6%9B%B4%E3%81%99%E3%82%8B">3. プロジェクトを変更する</a></h3> <pre><code class="bash"># プロジェクトの設定 $ gcloud config set project [PROJECT] # 現在の設定情報の確認 $ gcloud info </code></pre> <p>参考: <a target="_blank" rel="nofollow noopener" href="https://cloud.google.com/sdk/docs/configurations">SDK 構成の管理  |  Cloud SDK のドキュメント  |  Google Cloud</a></p> <h3 id="4. アカウントを変更する"><a href="#4.+%E3%82%A2%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%82%92%E5%A4%89%E6%9B%B4%E3%81%99%E3%82%8B">4. アカウントを変更する</a></h3> <pre><code class="console"># アカウントの設定 $ gcloud config set account [ACCOUNT] # 設定したアカウントの認証 $ gcloud auth login # 登録しているアカウントの一覧を確認 $ gcloud auth list # プロジェクトの設定 $ gcloud config set project [PROJECT] # 現在の設定情報の確認 $ gcloud info </code></pre> <p>参考: <a target="_blank" rel="nofollow noopener" href="https://cloud.google.com/sdk/docs/authorizing">Cloud SDK ツールの承認  |  Cloud SDK のドキュメント  |  Google Cloud</a></p> <h3 id="5. バックアップを別のプロジェクトにインポートする"><a href="#5.+%E3%83%90%E3%83%83%E3%82%AF%E3%82%A2%E3%83%83%E3%83%97%E3%82%92%E5%88%A5%E3%81%AE%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AB%E3%82%A4%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%88%E3%81%99%E3%82%8B">5. バックアップを別のプロジェクトにインポートする</a></h3> <p>全体の流れはこんな感じ。</p> <pre><code class="console"># バックアップしたいプロジェクトに設定 $ gcloud config set project [PROJECT] # 全体のエクスポート $ gcloud beta firestore export gs://[BUCKET_NAME] # 別のプロジェクトにプロジェクトに変更 $ gcloud config set project [PROJECT] # バックアップファイルのインポート $ gcloud beta firestore import gs://[BUCKET_NAME]/[EXPORT_PREFIX]/ </code></pre> <p><strong>注意点</strong></p> <ol> <li>インポートしたいプロジェクトのFirestoreは初期設定までする必要がある</li> <li>実行はプロジェクトのサービスアカウントで実行されるので、<br /> バックアップファイルのバケットに権限を付与する必要がある</li> </ol> <p>参考: <a target="_blank" rel="nofollow noopener" href="https://firebase.google.com/docs/firestore/manage-data/export-import?hl=ja">データのエクスポートとインポート  |  Firebase</a></p> <h1 id="おわりに"><a href="#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB">おわりに</a></h1> <p>有料のみではあるけど、</p> <ol> <li>本番データの分析したり</li> <li>本番データを開発用に利用したり</li> <li>プロジェクトの移行</li> </ol> <p>なんかにも使えそう。<br /> 分析はBigQueryを使えるならそのほうがいいかも?</p> <h2 id="こんなのつくってます!!"><a href="#%E3%81%93%E3%82%93%E3%81%AA%E3%81%AE%E3%81%A4%E3%81%8F%E3%81%A3%E3%81%A6%E3%81%BE%E3%81%99%21%21">こんなのつくってます!!</a></h2> <p>積読用の読書管理アプリ 『積読ハウマッチ』をリリースしました!<br /> <a target="_blank" rel="nofollow noopener" href="https://tsundoku.site">積読ハウマッチ</a>は、Nuxt.js+Firebaseで開発してます!</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/572d4947-f40b-e4dc-1c9c-bc584cd2a66c.png" width="200"/></p> <p>もしよかったら、遊んでみてくださいヽ(=´▽`=)ノ</p> <p>要望・感想・アドバイスなどあれば、<br /> 公式アカウント(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/MemoryLoverz">@MemoryLoverz</a>)や開発者(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/kira_puka">@kira_puka</a>)まで</p> <h1 id="参考にしたサイト"><a href="#%E5%8F%82%E8%80%83%E3%81%AB%E3%81%97%E3%81%9F%E3%82%B5%E3%82%A4%E3%83%88">参考にしたサイト</a></h1> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://firebase.google.com/docs/firestore/manage-data/export-import?hl=ja">データのエクスポートとインポート  |  Firebase</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://medium.com/google-cloud-jp/firestore-backup-67327a74cd54">Cloud Firestoreのバックアップ・リストア - google-cloud-jp - Medium</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://note.mu/yo16/n/ne25615bab8f5">gcloudのアカウント変更とプロジェクト変更|yo16|note</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/ShuA/items/1ff83b8d804168b087ba">自分用GCPコマンドリファレンス - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/Takakuwa-Shun/items/ac455c96a81a189eacce">gcloudの自分用メモ - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://blog.engineer.adways.net/entry/2018/06/08/150000">gcloudコマンド(GCP)で複数のプロジェクトとアカウントの使い分けを便利に - Adwaysエンジニアブログ</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/sakamossan/items/8ff74ed377dc77325b80">macosにgcloudとkubectlのインストール - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://cloud.google.com/sdk/docs/quickstart-macos?hl=ja">macOS 用のクイックスタート  |  Cloud SDK のドキュメント  |  Google Cloud</a></li> </ul> きらぷか@積読ハウマッチ/SSSAPIなど tag:crieit.net,2005:PublicArticle/15378 2019-09-04T22:16:22+09:00 2019-09-04T22:18:39+09:00 https://crieit.net/posts/Google-OAuth GoogleのOAuth認証で追加できないスコープがある時 <p>Google Cloud PlatformにはOAuth認証を用いたGoogleログイン機能がある。普段色々なところでよく見かけるとは思うが。このGCPのOAuth認証にはスコープというものがあり、デベロッパーがそれを指定することで認証だけでなく、合わせて様々なAPIの利用許可をログイン時に得て利用することができるようになっている。</p> <p>具体的にはGCPコンソールのOAuth 同意画面というところでスコープの追加を行うことができる。(実際にはアプリケーション側でも指定が必要)</p> <p>しかし、下記の画像のように鍵付きのスコープは条件によってチェックボックスが表示されず、追加できない場合がある。</p> <p><a href="https://crieit.now.sh/upload_images/c734987668aed5fa30c91a8dc2a587cd5d6fb6da58adf.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/c734987668aed5fa30c91a8dc2a587cd5d6fb6da58adf.png?mw=700" alt="" /></a></p> <p>プライベートデータにかかわるスコープのため、条件的に問題がある場合は選択できなくなっている。</p> <h2 id="原因"><a href="#%E5%8E%9F%E5%9B%A0">原因</a></h2> <p>調査&問い合わせをしてみたところ、どうも既にスコープを利用してしまっているアプリケーションの場合、コールバックURLにhttp始まりの非SSLのものが既に混じっていると追加できない、ということだった。そのため混じっている場合は削除が必要とのこと。しかし、この画面には大まかなURLを設定する箇所はあるが、具体的なURLを一覧できる場所が見つからない。これを放置していると「Action Required」メールが飛んできて、このままだと未承認でログイン時に警告が出るようになるぞ、と脅しが来る。</p> <p>で、よくよく探してみると「OAuth 同意画面」の方ではなく、「認証情報」のページに「OAuth 2.0 クライアント ID」の一覧がある。APIを開発する時に作成したもの。</p> <p>これの名前をクリックすると無事コールバックURLの一覧が見つかった。</p> <p><a href="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5d6fb869487ee.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5d6fb869487ee.png?mw=700" alt="" /></a></p> <p>ここでhttpではじまるものを全て削除する。すると、スコープが追加できるようになった。</p> <h2 id="Googleによる確認"><a href="#Google%E3%81%AB%E3%82%88%E3%82%8B%E7%A2%BA%E8%AA%8D">Googleによる確認</a></h2> <p>鍵付きのスコープを追加したあとは、Googleに承認をしてもらう必要がある。保存ボタンの右側にある「確認のための送信」を実行しておこう。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14471 2018-06-18T08:33:07+09:00 2018-10-31T17:00:15+09:00 https://crieit.net/posts/Google-Cloud-Storage-DB Google Cloud Storage無料DBバックアップ <p>サービスを運用していると、データベースのバックアップが必要になります。ただ、同じサーバー内にバックアップを保存すると、サーバーが壊れた際にまるごと紛失してしまいます。</p> <p>そんな時、Google Cloud Storageだと無料でデータベースのバックアップを保存できるため非常に便利です。</p> <h2 id="無料枠の詳細"><a href="#%E7%84%A1%E6%96%99%E6%9E%A0%E3%81%AE%E8%A9%B3%E7%B4%B0">無料枠の詳細</a></h2> <h3 id="容量5GBまでは無料"><a href="#%E5%AE%B9%E9%87%8F5GB%E3%81%BE%E3%81%A7%E3%81%AF%E7%84%A1%E6%96%99">容量5GBまでは無料</a></h3> <p>Always Freeにより、下記はずっと無料になっています。</p> <ul> <li>5 GB の Regional Storage(米国リージョンのみ)</li> <li>5000 回のクラス A オペレーション(1 か月あたり)</li> <li>50000 回のクラス B オペレーション(1 か月あたり)</li> <li>1 GB の北米から全リージョン宛て下りネットワーク(1 か月あたり、中国およびオーストラリアを除く)</li> </ul> <p>上記の通り、米国リージョンでGoogle Cloud Storageのバケットを作成しておくと、5GBまでは無料になります。DBのバックアップであれば速度は関係ないため、米国で良いと思います。</p> <p>Google Cloud Storageにバックアップする総容量が5GBを超えると費用がかかってきてしまいます。</p> <h3 id="通信料も無料"><a href="#%E9%80%9A%E4%BF%A1%E6%96%99%E3%82%82%E7%84%A1%E6%96%99">通信料も無料</a></h3> <p>上り(Google Cloud Storageへのアップロード)は基本的に無料です。バックアップする際は特に気にすることはありません。</p> <p>下り(Google Cloud Storageからのダウンロード)は、前述の無料枠の通り、1GBまでは無料となっています。北米のリージョンにバケットを作って運用しましょう。</p> <h2 id="Google Compute Engineからだったら楽"><a href="#Google+Compute+Engine%E3%81%8B%E3%82%89%E3%81%A0%E3%81%A3%E3%81%9F%E3%82%89%E6%A5%BD">Google Compute Engineからだったら楽</a></h2> <p>Google Compute Engineからバックアップを行う場合、非常に楽です。</p> <p>というのも、Google Compute Engineには最初からGoogle Cloud Storageへのアップロードに必要な<code>gcloud</code>や<code>gsutil</code>が元々入っており、しかも最初から認証済みになっています。そのため、ほとんど事前準備もなくコマンドを叩くだけでバックアップを行うことができます。</p> <p>バケットなどは事前に作っておきましょう。(非公開にしましょう)</p> <p>僕は下記のようなバックアップスクリプトを作成しました。<br /> (gsutilのパスは適宜実際のものとあわせてください)</p> <pre><code class="sh">rm backup.sql.gz mysqldump -u dbuser --password=hogehoge dbname > backup.sql gzip backup.sql /snap/bin/gsutil cp gs://backup-bucket/2.sql.gz gs://backup-bucket/3.sql.gz /snap/bin/gsutil cp gs://backup-bucket/1.sql.gz gs://backup-bucket/2.sql.gz /snap/bin/gsutil cp bakup.sql.gz gs://backup-bucket/1.sql.gz </code></pre> <p>3世代まで保存しています。容量に応じてこの辺は増やしたり減らしたりすれば良いと思います。</p> <p>GCP以外からの場合はkey fileを使って認証が必要なようです。</p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>何にしろAmazon S3等と違い、Google Cloud Storageは年間クレジットだけでなく永久無料枠があるのが大きな魅力です。さらに、GCPとの連携であれば初期設定も省くことができるのですぐに使えて便利です。ぜひ一度Google Cloud Storageの利用を試してみてください。</p> <p>※料金についてはその都度実際に確認を行ってください。</p> だら@Crieit開発者