大学祭のシステムをフルGCPで運用してみた

10/31〜11/01に、東洋大学 赤羽台キャンパスの大学祭「INIAD-FES」はオンラインで開催となりました。 その際のシステムを、GCPでホストしたので、その時のシステムの構成や、構成してみての感想をまとめてみたというお話です。

なおここでは開発したシステムなどの詳細には触れません

↓にも同じ内容を掲載しています qiita.com

どんな大学祭?

今年はCOVID-19の影響が続く中、多くの大学祭がオンライン上での開催を余儀なくされました。 INIAD-FESも例外ではありませんでしたが、多くの大学祭でライブ配信+Webページ上での掲示にとどまったものになっているのに対して、Webページ上で(できるだけ)キャンパスを再現→ライブ配信や静的コンテンツを掲載するという形としました。 できるだけ、キャンパス内の雰囲気を感じてもらおうというコンセプトです。

使ったサービスたち

Google Kubernetes Engine

最も要となるものです。

  • 会場サイト フロントエンド(React + nginx)・バックエンド(Rails
  • 入構管理システム(Django
  • 動画配信サーバー(nginx)

などをホストしました。 これらは、ユーザーが触れるシステムであり、VMを直接は触りたくない(運用が大変なので)・負荷分散を行いたいという理由で、GKEを使用しました。

GKEの負荷分散は、Google ManagedなSSL証明書を無料で使用できるので、とても便利ですが、もうちょっと発行早くしてくれないかなぁって所感です。 なお、static-ipは先に予約しておいて、予めDNSレコードに登録しておいたほうが後が幸せ。

自分はDockerを雰囲気で使ってる人間なので、当初は「え、ただの仮想マシン的なやつでしょ?」と思って、入構管理システムでcronを叩くようにしたら爆死しました。 DjangoのContainerではDjangoしか動かないんですね・・・

なお、こんな感じのyamlを書いてあげれば、CronJobとしてGKEに登録が可能です。 確かに、これはこれでお行儀がいいなと感じました。

apiVersion: batch/v1beta1
kind: CronJob
metadata:
    name: sendmail
    namespace: health-reception
spec:
    schedule: "0 4,8,14 * * *"
    jobTemplate:
        spec:
            template:
                spec:
                    containers:
                      - name: sendmail
                        image: dummy
                        args:
                          - python3
                          - manage.py
                          - send_alert_mail
                        env:
                    restartPolicy: OnFailure

GCPロードバランサーは、WebSocketに対応しているんですが、なんかやたらめったら切断されるなぁって思ったら、設定されたタイムアウト時間で一旦切断されるんですね。 configを書いて、serviceの設定に適用するようにすれば、ひとまず問題を回避できました。

↓のbeta.cloud.google.com/backend-configで設定を適用しています。 ingressの方へはreadinessProbeと同じく、serviceの設定が伝わるようで、特に設定しなくても大丈夫でした。

apiVersion: cloud.google.com/v1beta1
kind: BackendConfig
metadata:
  name: venue-backend-config
  namespace: venue-backend
spec:
  timeoutSec: 3600
---
apiVersion: v1
kind: Service
metadata:
  annotations:
    beta.cloud.google.com/backend-config: '{"ports": {"3000":"venue-backend-config","443":"venue-backend-config"}}'
  labels:
    app: venue-backend
  name: venue-deployment-service
  namespace: venue-backend
spec:
  externalTrafficPolicy: Cluster
  ports:
  - name: 80-to-80-tcp
    nodePort: 31377
    port: 80
    protocol: TCP
    targetPort: 80
  - name: 3001-to-3000
    nodePort: 31401
    port: 3001
    protocol: TCP
    targetPort: 3000
  - name: 3000-to-3000-tcp
    nodePort: 30323
    port: 3000
    protocol: TCP
    targetPort: 3000
  - name: 3002-to-3000-tcp
    nodePort: 30472
    port: 3002
    protocol: TCP
    targetPort: 3000
  selector:
    app: venue-backend
  sessionAffinity: None
  type: NodePort

ただ、WebSocketはそれだけでポートを1つ占有し続けることになるので、あまりお行儀は良くないのかもしれませんね。

Google Cloud Storage

静的コンテンツのホストをしました。 キャッシュが行われて、変更が即座に反映されないというのが、ありがたいのだろうけどちょっと泣かされました。 単純なWebサイトであればホストできるんじゃね?って思ったんですが甘かった・・・

Cloud SQL

Postgresで、会場サイトや入構管理システムのデータを保持しました。 最初はDeployment内にPostgresのコンテナをもたせていたのですが、GKEのPersistent VolumeがReadWriteManyに対応しておらず、スケールできないことが開発途中で判明したので、急遽の変更です。

できるだけPaaSを使いましょうねってことですね。

Cloud Memorystore

Railsのチャット関係で、ActionCableを採用したことから、Redisのために使用しました。 結構高いので、一瞬躊躇したのですが、Cloud SQLと同じく、Deployment内に持たせているとPersistent Volumeの問題でスケールできなくなるため、採用 純粋なRedisだと思ってたら、Rails6の仕様との兼ね合いでトラブりました(参考

Cloud Build

これは初めて使いました。 自分はCI/CDは使ってこなかったのですが、開発メンバー からの圧力により が多め(当社比)で、デプロイの自動化は必要となったための採用です。 GitlabのCI/CDは無料でできる範囲に制限があること(途中で使い切りました)、GKEやGCRなどGCPのサービスへの権限をかんたんに付与できるということで、とても重宝しました。 なお、GCPサービスへの権限付与は、サービスアカウントを有効化するだけです、簡単ですね。

運用してみての感想

GCPかなり活用したつもりですが、実際にはVPCを意識していないなど、結構問題アリアリな感じです。 個人でGCP運用しているのにも活かせる知見は得られたんじゃないかなぁと思います。

あと、GKEで運用していた部分をGAEに置き換えた場合というのも、ちょっと興味あります。 そもそもGKEで運用するべきだったのかという辺りも、また探ってみたいと思いました。

at INIAD生の皆様 INIAD-FES実行委員会、エンジニアが深刻なレベルで不足中です。 実行委員会で↑みたいな大規模システムの運用、してみませんか?