inol

https://github.com/hackz-hackathon-giganoto/team-kankodori

Go

TypeScript

React

Azure

Kubernetes

願い事・叶えたいことを inol で祈誓(きせい)しよう!

Takamichi Omori

推しアイデア

みんな願い事あると思います!神社に出向くのは難しくても、inol でお願い事しましょう! 絵馬はなくなっちゃうかもしれないけど、inol でつくった絵馬なら NFT になるので一生なくなりません!!!

作った背景

> き-せい 【祈誓】 神仏に誓いを立て、加護を祈ること。 きせいから連想できる言葉で、一番しっくりきた言葉が祈誓でした! みんなで祈りましょう🙏

推し技術

Remix(React)/TypeScript/手作りのキャンバス/WebRTC/Azure/Azure Blob storage/Azure Kubernetes Service/CockroachDB/ LINE Blockchain/GitHub

プロジェクト詳細

inol

inol を使うことで、インターネット上で祈りを絵馬や恋の南京錠といった形で捧げることができます!

神社に行くことは難しいご時世ですが、 inol を使って祈ってみましょう!

イチオシ機能

  • キャンバス
    • 同時編集も可能
  • 書いたイノりのNFT化
  • OGP 生成

キャンバス

  • スマートフォン・パソコンの両方に対応したキャンバスです。
  • 線の色は三色から選ぶことができ、消しゴムもあります。
  • 絵を書くために、マウスダウン状態で線を引いているタイミングは Canvas に、マウスアップにより確定された線は SVG を用いて描画されます。
  • 今回は、描画ツールをペンに限定することで SVG による保存を可能にし、ファイルサイズの空間計算量とレンダリングの時間計算量を削減しています

同時編集機能

  • inol では、作成ページのURLを共有することで 同時に同じアイテムに文字や絵を書くことができます
  • 同時編集機能は WebRTC(P2P) を用いています
  • 通信プロトコルやキャンパス自体もライブラリには依存せず、フルスクラッチで書いています。
  • ネットワーク層には抽象化層を挟むことで通信方法をWebRTC以外に切り替えることも可能にしています。

書いたアイテムのNFT化

  • 近年、Web3.0やNFTといった言葉をよく聞くようになりました。
  • inol で捧げたイノりは、LINE Blockchain 上に NFT として作成され、ユーザのウォレットに付与することが可能です。

OGP 生成

イノりを各種SNSにシェアすると、書いたイノりが OGP として表示されます。

イノりは SVG で動的に生成しているため、 PNG などのラスタ画像が必須になる OG Image として使用することはできません。 そこで、SVG から PNG を作成するために、メンバーが作成したsvg2png-wasm(Zenn)svg2png-deno-deployを利用しています。

使用した技術

フロントエンド

  • Remix
    • 比較的最近リリースされたReactのフルスタックフレームワーク。キャッチアップと、一部メンバーの「Svelte以外も書けるんだゾ!」という思いで選定
  • React
    • Remixを選定したため選定
  • TypeScript
    • 型無しでは生きていけない体に育ってしまったため選定
  • tailwindcss
    • Remixとの噛み合わせを鑑みてCSSinJSなどの選択が不適当であると判断したため選定

バックエンド

  • Go
    • Dockernize が簡単 && 書きなれている
  • Echo
    • 軽量なウェブフレームワーク

インフラ

  • Azure - AzurePass を頂いたのありがたく使わせていただきました m(__)m
  • Cloudflare
  • Ayame Labo
    • WebRTC のシグナリングサーバとして利用
  • CockroachDB
    • 分散SQLデータベース
      • PostgreSQL 互換のインターフェイスをもち、水平スケールできる
    • AKS内に自分でホストしています
  • LINE Blockchain
    • NFT の生成・管理に利用
  • LINE BITMAX Wallet
    • ユーザがNFTの管理するために利用

リポジトリの使い方

inol に関連するコードは GitHub で管理されています。

$ tree -L 1 . ├── README.md ├── backend ├── brand ├── docs ├── frontend └── infra 5 directories, 1 file

リポジトリは frontend, backend, infra のようなディレクトリにわかれていて、それぞれの領域のコードが保存されています。

docs には API仕様や、各種シーケンス図などが置かれていて、サービスを開発するときに参照しています。 メンバーのコミュニケーションは IssuesPull Requests を中心に行っており、ハッカソン中でも殆どの Pull Request は他のメンバーによるレビューを受けながら開発を進めていました。

開発体験

PR がマージされると、frontend, backend ともにデプロイが始まります。 backend のサービスは自動で docker build され Azure Container Registory への push が行われます。その後、AKS へのデプロイが行われます(kubectl set image)。 frontend のサービスは Cloudflare Pages(Edge Worker) に デプロイされます。 こうすることで、常に main の状態が各種エンドポイントに反映される状態になっています。

バックエンドの開発体験

バックエンドは nginx-ingress-controller を用いて、開発環境と本番環境がホスト名で別れています。(api.inol.cf, onsd.inol.cf) onsd.inol.cf に来たリクエストは telepresence を用いることで、手元のラップトップにルーティングすることができます。 telepresence を利用すると、ラップトップからクラスタ内に通信を行うことができます。 この方法を用いることで、手元にDBを用意することなく、クラスタ内のDBを使って開発を行うことができます。 このように開発を行うことで、 api.inol.cf は main が常に出ている状態を担保し、バックエンドの開発には onsd.inol.cf を使うことでフロントエンド開発の邪魔になることなく、開発を行うようにしました。

フロントエンドの開発体験

フロントエンドは先のように、 main ブランチがデプロイされるのはもちろんですが、Cloudflare Pagesの機能により Pull Request を生成するたびに各コミットがデプロイされます。 特にLIFFの開発ではngrokといったトンネリングを用いることが多いですが、今回はそれらの利用は最小限にすることができました。

アーキテクチャ図

サービスに関係する図

開発に関係するコンポーネント

クラスタ内のコンポーネント

$ kubectl get ns NAME STATUS AGE aks-helloworld Active 4d8h # AKS の動作確認に利用 ambassador Active 4d6h # telepresence の利用に必要なコンポーネント cockroach-operator-system Active 3d6h # CockroachDB のデプロイに利用 cockroachdb Active 3d6h # CockroachDB default Active 4d11h item-api Active 2d6h # 今回のバックエンドサーバ kube-node-lease Active 4d11h kube-public Active 4d11h kube-system Active 4d11h nginx-ingress Active 4d8h # ホスト名やパスを用いたルーティングに利用 onsd-item-api Active 41h # 開発用デプロイメント redis Active 4d7h # websocket サーバをスケールさせるために利用 ws-server Active 4d8h # WebRTC が利用できなくなったときのフォールバック

nginx-ingress の設定

$ kubectl get ing -A | grep item-api NAMESPACE NAME CLASS HOSTS ADDRESS PORTS AGE item-api item-api-ingress <none> api.inol.cf 20.231.70.43 80 2d6h onsd-item-api onsd-item-api-ingress <none> onsd.inol.cf 20.231.70.43 80 41h

onsd.inol.cf にきたリクエストは onsd-item-api namespace の service に流し、 api.inol.cf に来たリクエストは item-api namespace の service に流す設定

Takamichi Omori

@onsd