Open Hack U で優秀賞を取った件について
はじめまして Q です。ヤフー(株)が主催するハッカソン、Open Hack U 2020 Online Vol.4にチーム「ねこ」参加して優秀賞を取りました!!! 一緒に参加してくれた仲間に感謝です!さて、Open Hack Uで作った作品と担当してやったことについて書きます。
作品について
背景と目的
Open Hack Uをはじめとするハッカソンではチームで参加することが求められます。ハッカソンに参加するにあたって、メンバーを探す必要がありますが、 アイデアがないとメンバーを探すのが難しかったり、欲しい分野の人を見つけられなかったりすることがあります。 例えば、「ねこ」でもインフラ担当を探すのに苦労していたそうですし、デザイナーは見つけられませんでした。 このように、ハッカソンではチームメンバーを募集する人とチームで参加する人の間で
のマッチングがなかなかうまく行かないという課題があります。
そこでOpen Hack Uでハッカソンのチームメイト募集に特化したHackUPというサービスを構築しました。
特徴
背景で書いた課題を解決するために以下に書く特徴を盛り込みました。
技術とアイデアをマッチングさせやすい仕組み
アイデアがある人は技術のある人を募集し、技術のある人はアイデアがある人を探せる仕組みになっています。
異なる分野の人や募集を見つけられる仕組み
募集や参加希望には - フロント - サーバー - インフラ - デザイン の4つのカテゴリを設定できて異なる分野の人を見つけられることができます。 募集も同様にカテゴリ分けができるので必要な分野の人を見つけやすくなっています。
オープンに探せる仕組み
募集、アピールともに動的にOGPが生成されます
OGPの生成は自前で行うのが難しかったのでVercelを利用しています。
担当
フロントエンド、バックエンド、インフラの3つで別れて分担しました。
アーキテクチャ
アーキテクチャを図に示します。フロントエンドをNext.js、バックエンドをGoで書き、APIをGraphQLで構築しました。 バックエンドのGoアプリケーションとPostgreSQLはDockerでコンテナ化し、NginxでHTTPSの終端を処理してリバースプロキシになっています。 動的ルーティングの都合でNext.jsの一部がサーバーサイドで動いています。node.jsをpm2でデーモン化しています。
デプロイ先はConoHaのVPSとなっています。また、GitHub actionsを用いてCI/CDを行い、Prometheusで監視してGrafanaで可視化しました。Prometheus、GrafanaもDockerで管理しています。
一方で構築や運用が自前で難しいものは外部サービスを利用しました。
- OGPの生成にVercel
- 認証はFirebase
- メール送信はSendGrid
- DNSはcloudflare (図にありません)
Qの担当分野
技術選定
インフラ担当ということで技術選定のインフラ側を行いました。 以下の技術選定の方針で選定しました。
- 高性能でスケーリングできるようにする
- クラウドサービスのベンダーロックインを避ける
- 極力自分で管理できる場所を増やす
- できるものはコードにする
- 管理が大変なツールは使わない
1.高性能なのは文字通りで、Nginxを選定したのは大量のリクエストをさばくことができるからです。 スケーリングできるようにするのはサーバーを増強したらそのままサービスが拡張できる構成にすることです。 ゆくゆくはK8sによる管理を考えてDockerでコンテナ化し、高速なGoをサーバーサイドに選定しました。
2.のクラウドサービスのベンダーロックインを避けるのは序盤の開発では何が必要かもあまりわからないので、 クラウドサービスに依存しすぎた構成は良くないと考えたからです。この例としてDockerコンテナと一般的なVPSで構築してある程度融通がきくようにしました。
3.の極力自分で管理できる場所を増やすのは、設定項目が増えるのでバランスを取るのが難しいですが、かゆいところに手が届くことを目指しました。
4.のできるものはコードにするというのはそのまま Infrastructure as Code です。設定を把握しやすくしたり、自動化による作業ミスの削減のためです。
5.管理が大変なツールを使わないというのは前述の1~4に矛盾することもありますが、自前主義に陥って本末転倒にならないようにするという意味です。また、ハッカソンなので本筋から外れたことに労力を割きたくないという思惑もありました。DNS、メール、OGP生成は明らかに大変なのでマネージドサービスを使いました。
認証は最初はSupertokensを利用しようと考えて失敗したり、node.jsのサーバーサイド処理がgdgdになったりと上手く行かなかった所はありましたが、今の所運用に困っていないので及第点ではあると思っています。
運用体制
Docker とGoを本番運用する点とGitHub actionsを使うのが初めてでそこは不安で、序盤はなかなかうまく行かなかったのですが後述する方法でなんとか上手く動くようになりました。
運用を整えて他のメンバーがインフラを意識しない状態を理想として取り組みましたが設定に不備があったり予期せぬことが起こったりとあって理想とは程遠い状態になりました。運用でPrometheusやGrafanaが入ったのも終盤でドタバタでした。最後の最後に監視でメモリー不足が発覚してサーバーを増強できたので監視とその対応は最低限できたと思っています。
CI/CD
ここが今回で一番難産だった場所です。フロントエンドが難しかったです。
フロントエンドはビルドとnode.jsサーバーの再起動があり、デプロイをGitHub actions だけで完結させるのが難しかったので
- git pull
- ビルド
- node.jsサーバーの再起動
を行うシェルスクリプトをデプロイ先のサーバーに置いて、GitHub actionsでSSHでスクリプトを起動するようにしました。SSHキーを外部に置くのはセキュリティーに悪影響を及ぼすので2点の対策をしました。SSHコマンドには引数を一切入れないようにし、SSHコマンドもauthorized_keysで実行できるファイルをデプロイのスクリプトに限定することでSSHキーの権限をできる限り小さくしました。
バックエンド側はDockerコンテナをビルドし、デプロイする処理をGitHub actionsで記述しました。デプロイ先にスクリプトを置き、SSHでスクリプトを起動するようにしました。セキュリティー対策はフロントエンドと同様にしています。
今後の課題
一番大きな課題は監視体制の整備です。今の状態で監視できているのがDockerコンテナとサーバー全体だけでnode.jsサーバーとNginxは監視ができていません。またGoのアプリの内部もブラックボックスになっています。アプリ内部に監視ポイントを用意して全ての監視ができるようにしたいと考えています。node.jsサーバーをpm2でデーモン化していますが、pm2の監視に関してドキュメントが少なく、pm2の監視が大きな課題になりそうです。
次の課題がログ収集とその分析です。今の状態だとログ収集は一切行っておらず、Qが定期的にSSHしてログを見ています。ログのフォーマットもバラバラで分析に困っています。全てのログの形式をJSONに統一してGrafana Lokiでログ収集基盤を作ることを考えています。
おわりに
初めてのハッカソンでチームメンバーと完全オンラインで不安もありましたがなんとかものにできました。メンバーのみなさんとヤフー(株)のメンターの皆様に感謝申し上げます。
関連項目
チームメイトのLe0tk0kさんとmarinaさんがブロクを書いています。