みなさんこんにちは、elcaです!
早速ですがみなさん、SAKITOってご存知ですか??詳しくは後述しますが、学生団体CirKitが開発、運用している学内向けサービスとなっています。
今回はそのサービスをインフラ移行する計画のリーダーとして色々と活動したので、その報告をしていきたいと思います。
はじめに
自己紹介
改めまして、elcaです!
現在は金沢工業大学の課外活動、学生団体CirKitに所属しています。
略歴としては、2024年度の新人採用研修チーム(採用、研修を担当するチーム)のマネージャーを務めており、現在はSAKITOのインフラリーダーとして活動しています。
略歴だけだとなんの分野が得意なのかぱっと見分からないと思いますが、実は私、バックエンドエンジニアを目指しています。
CirKitについて
CirKitは通常の学生団体とは少し異なり、会社という立ち位置になっています。
展開しているサービスとしては、@連絡網やSAKITOが代表的です。
またカフェ営業も行っており、本学の文化祭「工大祭」や卒業式などに営業しています。その際に使用している注文システムはCirKitで開発した「ロゴスシステムズ」を使用しています。
SAKITOについて
SAKITOは学内向けに展開しているサービスです。
ユーザはアンケートを作成することができ、そのアンケートに他のユーザが回答します。アンケートに回答するとポイントがもらえ、そのポイントでガチャを回します。当たれば、学食や学内コンビニの無料引換券がもらえます!
本学ではプロジェクトデザインなど、他の学生からのアンケートを必要とする科目があるため、それに利用する学生もいますし、ただただ「〇〇ってアーティスト知ってる??」といった内容のアンケートもあり、割と自由にアンケートを出し、それらに回答しています。
きっかけ
さて、ここからが本題、インフラ移行についてのお話です。
まず、なぜインフラ移行をしようとしたのかのきっかけを紹介します。
1. PaaS
今まではrailwayと呼ばれるPaaSを利用していました。
しかし、リージョン変更などのバージョンアップによって時々SAKITOのサービスが停止する問題が発生していました。時差の影響で、ユーザの利用頻度の少ない時間にサービス停止したので、ユーザに対する影響はそこまで大きくはないかと思います。しかしrailwayは頻繁にバージョンアップを行うため、気づかないうちに一部機能が使えない、という状況になる可能性があります。
そのため、PaaSを脱却して、インフラをSAKITOで管理しようという流れになりました。
2. 成長と挑戦
これは定性的な話になりますし、実際の企業ではこの理由でインフラ移行するなんてもってのほかだと思いますが、まぁここは学生団体ならではの理由ということにしてください笑
CirKitは学生としてはレベルの高い知識や技術を必要とします。もちろん得意不得意はあるかもしれませんが、これは必ず社会人になる上での成長につながります。
また、誰でも挑戦できる環境が整っているのも特徴の一つです。失敗を元に次に活かす、そんなアグレッシブなことだってできちゃいます。
PaaSよりもAWSを利用することで、当然学習コスト、運用コストが高くなります。
ただ学生の成長と挑戦にフォーカスした時、AWSの方が効果的だと私は考えました。
構成
構成としてはアプリケーションをApp Runnerで動かす方針にしました。
また、アプリケーション開発時の体験を、railwayとほぼ同じにするため、mainブランチにマージされたら自動的にECRにイメージをpush、App Runnerがこれを検知し自動でデプロイするようにしました。その他、作業効率を上げるためにCI/CDをGitHub Actionsによって実現しました。
工夫したところ
CDKの導入
インフラを構築するにあたって、IaCの導入は必須と考えていました。今後のアプリケーション開発などでAWSを利用する際に、IaCならコピペで間違いなくインフラ構成を複製できるからです。
候補としてはterraformが真っ先に上がりましたが、独自の言語を使用する点、AWS公式サポートではない点などから、CDKにしました。CDKは既存のプログラム言語で記述することができるので、学習コストが比較的低く、またドキュメントに関しても公式が出しており、しかも分かりやすいといったメリットがあります。
なお、採用した言語はTypeScriptになります。CirKitではエンジニア研修時にJavaScriptを教えているため、TypeScript自体に対する学習コストが低いという考えでこの言語を採用しました。
コスト削減
railwayに比べて非常に高く付くと見込まれていたAWS。できる限り費用を抑えるために、様々な工夫をしてきました。
1.踏み台サーバの管理
小さく注釈にある通り、踏み台サーバとアプリケーションとでCDK側でStackを分けています。
極力無駄なサーバを構築させないためにも、踏み台サーバを利用していないときはサーバを削除するようにしています。踏み台サーバとアプリケーションとでデプロイのタイミングが異なるため、Stackを分けているというわけです。
なお構築と削除を簡単に行うために、GitHub Actionsにて手動で構築と削除を行えるようにしています。
const app = new cdk.App();
/* アプリケーション用のStack */
const sakitoCdkStack = new SakitoCdkStack(app, 'SakitoCdkStack', {
env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
});
/* 踏み台サーバ用のStack */
const sakitoBastionStack = new SakitoBastionStack(app, 'SakitoBastionStack', {
network: sakitoCdkStack.network, // アプリケーションのネットワークを利用
env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
});
sakitoBastionStack.addDependency(sakitoCdkStack); // 依存関係を定義
2. RDSのSingle-AZ化
通常AWSのベストプラクティスでは、Multi-AZにした方がいいのですが、これだと単純計算RDS複数台分の料金が取られます。SAKITOの規模感的にもMulti-AZは過剰な性能となるので、Single-AZで対応しました。
CI/CDの活用
冒頭にも説明した通り、今回はCI/CDを最大限活用しました。
例えばSAKITO-CDKリポジトリを例に挙げましょう。このリポジトリはその名の通り、CDKを管理するためのリポジトリなのですが、ちょっと特殊なブランチ構成となっています。
まず main ブランチは従来通り、基本的に全てのPRをマージする先となるブランチです。
そして本番環境に反映したくなったタイミングで、 main ブランチから production ブランチにPRを発行、マージします。すると、GitHub Actionsが自動的に本番環境に反映させてくれます。
ステージング環境も同様で、 main ブランチから develop ブランチにPRを発行し、マージさせることで、自動的にステージング環境へ適用されます。
なぜこのようなちょっと特殊なブランチ構成になっているのかというと、 cdk deploy といったデプロイ関連のコマンドをGitHub Actions上で全て完結させたかったからです。こうすることで、開発者自身のローカル上で実行する必要がありませんので、属人化がなくなりますし、間違えてステージング環境じゃなくて本番環境に実験用の環境を反映させてしまった、といった事故がなくなります。
テスト
気付かないうちにセキュリティホールがあった、なんてことがないように、テストを追加しています。
テストにはいくつか種類がありますが、今のところFine-grained assertionsテストを追加しています。
ただCDKのバージョンアップやリファクタリング専用として、スナップショットテストも導入したいですね。
今後の展望
Slackとの連携をしたい!
やはりまず初めはこれに尽きると思います。
現状、特にSlackとの連携はしていないため、デプロイが成功しているかの通知はもちろん、アプリケーションが正しく動いているかの通知も来ません。chatbotなどを利用してその点を実装していきたいですね。
統計
月の利用者数や新規登録者の推移などをグラフ化して、定期的にSlackに流したいです。
これによって、施策の効果が定量的にわかるので、その施策が効果的だったかどうかの比較ができます。
最後に
11月はじめに本番環境への完全移行は完了していますが、まだまだ改善点や改良点はあります。それらの点を後輩を中心に取り掛かってもらい、私は後輩のサポートに徹しようと考えています。

