かれこれ2年くらい運用している Django の社内システムがあって、この度晴れてさくら VPS から GKE に載せ替えてみた...というお話形式の投稿。
背景
この社内システムは、もともと「CSV 形式の配送先から PDF 形式の宛名ラベルに変換する」などの便利ツールの集合体で、つくった当初は会社自体が立ち上げたばかりだったので、最安でデプロイできる さくら VPS にお世話になっていた。ところが、だんだんと会社が大きくなるにつれてシステムの機能も増えていき、今日では在庫管理や SNS 用の画像生成までこのシステムが担っている。
ユーザは10人いるかいないかなので、スペックの要求はそんなに高くないものの、画像生成のジョブが OOM Killer に殺されがちなことや、ディスク拡張したときに VPS のスケールアップの大変さを実感したことから、GCP の何かしらのサービスに移行したい気持ちになっていた。
選定
Django の移行先としては、まず自分が経験したことのある Cloud Run が第一候補に上がった。ただ、 Cloud Run にする場合、もともと Celery で書いていたジョブを Cloud Tasks などにサーバレスに書き換える工数があったので、docker-compose の構成を比較的そのまま使える GKE を使うことにした。もう1つの理由としてはシンプルに「使ってみたい」というもので、これまで k8s/GKE がまったくの未経験だったので、どんなもんやろという感じで選定した (1人エンジニアだしコストも使っていいとのことだったので問題ない)。
k8s 入門
学習リソースは主に次の3つだった。
- つくって、壊して、直して学ぶ Kubernetes入門(高橋 あおい 五十嵐 綾)|翔泳社の本
- くわしい友だち
- たまたま本業でもらったサンプルコード
ツイッターで本当にたまたまあおいさんの「つくって、壊して、直して学ぶ Kubernetes 入門」の宣伝が流れてきて、2 の友だちに「これ気になってるんだよね」という話をしたら一緒に進めることになった。輪読という感じではないけど、Discord でつなぎながら各自で本を消化していった。
本業の方では、全く関係ないプロジェクトで k8s のマニフェストファイルをもらったので、ローカルでいろいろ試していた。
compose manifest → k8s manifest
一通り本を読み終わったら、さっそくシステムの docker-compose.yaml を k8s 用の YAML に変換する作業をはじめた。Qiita とかを見ると kompose がおすすめされていたので使ってみたけど、使い方が悪かったのか全然うまくいかなかった。いずれにせよ自動生成されたファイルだと何が起きているかまったくわからないので、compose manifest を ChatGPT (4o) に食わせて k8s 用のファイルを作ってもらった。
当然ファイルを見ただけではさっぱりなので、わからないところは随時 ChatGPT 先生に聞きながらマニフェストを作っていった。正直ここの作業は ChatGPT がなかったら相当ハードルが上がったきがする。
Terraform
一通り動きそうな k8s manifest ができた段階で、今度はインフラの準備をした。ちょうど本業で Terraform を触り始めたタイミングで本業で使ってないリソースを書こうとしたので、こっちはこっちで another beast という感じだった。とくに VPC peering とか GKE の各リソースの定義がわからなくて、 Terraform docs といったりきたりしていた。
アプリケーションコードの変更
もともとアプリケーションコードの変更を最小化するためにインフラで苦労する構成にしたので、ここは k8s・Terraform よりはハードじゃなかった。とはいえ DB の接続設定を変えるとか、これまでローカルのファイルシステムから読んでいた静的ファイルを GCS から読むためのパッケージを入れるとかをやる必要があったので、これもそれなりに骨の折れる作業だったし気の遣う部分だった。
とくに、せっかく GKE は Workload Identity に対応しているのに、 GCS をファイルストレージに使うための django-storages[google] のパッケージが対応していなくて、サービスアカウントキーを使わないといけないのがモヤった。とはいえこのパッケージを調べていくうちに Django の Storage クラスを掘れたのはよかった。
移行作業
...ここまでの変更はさらっと書いたものの、本業とか副業とか転職活動とかをしながら、期間としては2ヶ月くらいかかっていた。ようやく8月上旬で移行作業を実施するタイミングができたので、まずは予行演習をした。
手順書を用意するということを最近学んだので、それを読みつつやってみたところ予行演習「は」スムーズに行った。
ところが、しばらくしてからいざ本チャンで移行しようとしたところ、いくつかのトラブルに見舞われた。まず、予行演習では 20m くらいしかかかってなかったデータのエクスポート (python manage.py dumpdata) が3h ほどかかっていた。しかも、最初は verbose フラグをつけていなかったので、 1h くらいたったところで「実は裏でコケてるのでは?」とコマンドを kill してしまった。
データ移行が終わったあとも、ビルドを通してみたら静的ファイルがコピーされてなさそうなことに気づいて、調べてみたら Django の STATICFILES_DIRS に追加するのが抜けいたりということもあった。結局 23:00 に始めた作業が終わったのは 3:00 すぎてからで、翌日はだいぶグロッキーだった (別日にするとまた 3h データエクスポートを待たなきゃいけないので、意地でも終わらすぞという気合)。
移行翌日
さすがにバグ0とはいかなかったものの、基幹業務に影響があるものはなくてよかった。上がってきたバグ報告は移行翌日 (というか当日) に修正を出して、2-3日後には翌日以降に上がってきた分も全部つぶせた。
まとめ
... というほどでもないけど無事に終わってよかったし、ChatGPT のあるタイミングでこれができてよかった。