どうも、最近週末に映画を観るのが楽しみなtobi462です。ちなみにAmazon Prime Videoです。
今日はプライベートで作ったシステムの話、というか物語を書いてみたいと思います。
がんばるぞいbotとは
Slackで「がんばるぞい!」と書き込んだら、キャラクターが応援してくれるBotです。
ちょうど以下のような感じですね。
NEWGAME!という漫画の第一巻で有名になった「がんばるぞい」を活用したBotですね。
開発のキッカケ
開発のキッカケはシンプルで、 仕事前とか勉強前にがんばるって書き込んだら応援して欲しいな というものでした。
ペンギン村の住人でSlackのワークスペースを持っているのですが、そこの「newgame」チャンネルで活躍しています。
残念ながらSlackAppとして公開はしていませんが悪しからず。
歴史を振り返る
そんな(最初は)シンプルなBotだったのですが、システム構成やら機能やら様々な変化がありました。
実は今度「AWS Lambda」に移行しようと思っているのですが、その前に歴史を振り返ってみよう、というのが今回の記事です。
0. はじまり - Android / Kotlin アプリ時代
Slack用のBotのはずなのに、最初はなぜかAndroidアプリからのスタートでした。
当初、私はAndroid/Kotlinを勉強しようという意気込みにあふれており、せっかくなのでAndroidアプリからSlackにPostしてみようというノリでした。
ユーザ名などを設定画面で入力して「がんばるぞい」ボタンを押したらSlackにポストするという単純なものでしたが、記念すべき「がんばるぞいbot」の開発の始まりでもありました。
記念すべき最初の実装なので個人的にもとても懐かしいものです。
開発したアプリは alpha 版として公開することで、ペンギン村の住人に利用してもらえる状態にしました。
意外な問題
さて、初期バージョンを開発したのは良かったのですがすぐに課題がみつかりました。 それはペンギン村の住人でこのBotを使いたいユーザは全員iPhoneユーザということでした。
というわけで、初期のAndroid/Kotlinバージョンはあっという間に闇に消えました。
悲しいぞい・・・
1. 始動 - Swift / Vapor / Heroku 時代
そんなわけで、すぐに次の開発をスタートしました。 もはやモバイルを捨て、サーバサイドへ旅立つ必要がありました。
仕事でSwiftを多く触っていた私は、サーバサイドSwiftでやろうと決めました。
Let's Server Side Swift
構成は以下のとおりでした。
- Swift 4.x
- Vapor
- Heroku
サーバを自分で用意・管理するのが面倒だったので、PaaSであるHerokuを利用しました。
Vaporを選んだ強い理由はありませんが、過去にVaporとKituraを軽く触った時に、Vaporの方がシンプルだなと感じたのが大きいかもしれません。
分かっていた問題
さてHerokuは無料プランで使いました。
Herokuをご存知の方は、何が問題になるかよくご存知かと思います。 そう「スピンダウン」です。
Herokuは一定時間アクセスがないとインスタンスが止まってしまう(スピンダウン)ため、次回アクセス時に起動するまでに時間が掛かる(スピンアップ)という問題でした。
以前、Herokuを使ったことがあったので、この問題は事前によく分かっていました。
そこでクラウドのIaaSである「Digital Ocean」にサーバを立て、そこから定期的にアクセスするようにしました。Digital Oceanは、全てSSDで値段も安いと聞いたことがあったので、AWSやGCPではなくDigital Oceanを使ってみることにしてみました。
- DigitalOcean
- Ubuntu
- Digdag
定期アクセスであればcronで十分かと思ったのですが、仕事でDigdagを利用していたこともあり、せっかくなので使ってしまおうというノリでした。
Herokuを無料で利用するために$5/moなインスタンスを契約するというなんだかおかしな状況 になりましたが、問題は完璧に解決しました。
2. 激動 - Kotlin / Spark / Docker 時代
さて、こうして出来上がったがんばるぞいBotはなかなか人気で、毎朝「がんばるぞい」と書き込まれる毎日が続きました。
私自身もアクティブユーザとして、今日はどんなキャラが応援してくれるか楽しみにしていました。
がんばったぞいBot
さて、そうこうするうちに新しい機能が欲しくなりました。
「がんばるぞい」も良いけど、がんばったら褒めてほしくない? という単純な動機により「がんばったぞいbot」を作ることにしました。
いやはや我ながら素晴らしい機能だと思いました。
既存のサーバサイドSwiftに機能追加しても良かったのですが、その頃Kotlinに興味を持っており(ry
ということで以下のような構成でシステムを立ち上げました。
- Kotlin
- Spark
- MongoDB
- MongoExpress
- Docker (DockerCompose)
- Ubuntu
- DigitalOcean
ここで流行りのDockerも触ってみることにしました。勉強がてらというところです。
MongoDBにすべき強い理由はなかったのですが、なんとなくKVSやってみようくらいのノリでした。
CI/CD・さらなる機能追加
さて、ここまできたら自動ビルド・デプロイもしたくなりました。
ここまできたら全部マニュアルな感じてやってみよう、ということでJenkinsを使った自動ビルド・自動デプロイを実現しました。
自動デプロイはmasterブランチにマージされたら、それをトリガーにデプロイされる感じです。(Blue/Greenデプロイまではやりませんでした)
と、書くと簡単にできたようにも見えるのですが、まぁそのいろいろ苦労しました・・・あまり慣れていなかったこともあり。
そして「ゆんのティータイム」(15:00になったらティータイムに誘ってくれる)という機能を追加するため、こちらにもDigdagが導入されました。
追加されたコンポーネント:
- Jenkins
- Digdag
システム統合
さてこのあたりでペンギン村の住人の一人が開発メンバーに加わることになりました。
そして紆余曲折あり 「がんばるぞいbot」と「がんばったぞいbot」を統合する ことになりました。
まぁ元々別システムにしている理由がなかったので、統合できてよかったかと思います。
これにより2号である「Swift / Vapor / Heroku」によるBotは幕を閉じました。お疲れ様でした。
S3連携、さらなる機能追加
さて、もうここまできたらイケイケな感じです。
今時、画像データはS3に置くべきでしょ ということでAWSも使うことになりました。
そして、機能も思うがままに開発・デプロイし、利用者のフィードバックを楽しみにしていました。
そう・・・あの事件が起こるまでは・・・
AYBABTU
ある日、MongoExpressにアクセスしてみると奇妙な状況になっていました。
DBのデータは消えており、何やら怪しいデータが作成されています。 そして、データに残された英文を見ると、「お前たちのデータは頂いた。返してほしくば xx BTCを」と書かれています。
・・・ ランサム被害やんけ!
そしてデータはローカルに残っていたものを除いて失われてしまいました。 幸い、そこまで失われたデータは多くなかったのですが、個人的にショックでした。
原因
原因を調べたところ、犯人は意外なものでした。
Firewall(UFW)は設定しており、きちんとブロックされるはずのアクセスがなぜ通ってしまっていたのか。
端的にいうと以下の問題でした。 ngzm.hateblo.jp
個人的に手痛い失敗でしたが、多くを学ぶことが出来ました。
- 稼働後に外からアクセス出来ないことを確認すべき
- クラウドのFirewallも活用すべき
- 大事なデータはバックアップすること
まぁ当たり前の話かもしれません。 おそらくこれが業務であればいずれも実行したと思います。
しかし、プライベートでこういった事態に遭遇することが出来て、かえって良い経験ができた。そんな風に今は思っています。
自動バックアップ、管理画面追加、最終的なシステム構成
ここから先はそこまで大きな話はありません。
まずJenkinsのJobでMongoDBのデータを自動バックアップし、S3にアップするようにしました。
データの追加が面倒なので、Railsを使った管理画面も追加しました。なぜかこれはHerokuにデプロイしたのですが。
そして最終的なシステム構成は以下のようになりました。
- AWS
- S3
- DigitalOcean
- Kotlin / Spark
- MongoDB / MongoExpress
- Digdag
- Docker / DockerCompose
- Jenkins
- Ubuntu
- Heroku
- Ruby / Rails
メモリが不足する度にDigitalOceanのインスタンスをスケールアップした為、 $20/mo のインスタンスになっていました。
そこで気づきます。 これただのSlackのBotだよね? と。
3. 未来へ - AWS Lambda 時代?
自分で一からインフラも含めてやってみようということで、いろいろ試したシステムでしたが、 さすがにお金をかけすぎている とあらためて思いました。 もちろんそれが楽しかったので、良かったのですが。
さてBotという要件を考えると、リクエストが要求された時などごく短時間だけ計算リソースがあれば十分です。
そもそもBotの利用者も少なく、一日のうち利用している計算リソースの時間はおそらく30秒程度でしょう。(デプロイまわりはさておき)
そのために$20/moなインスタンスを24h稼働しているのはあまりにも無駄です。
なんだか結論ありきな書き方をしてしまいましたが、 そこで「AWS Lambda」ですよ というお話です。
新規に開発メンバーも一人加わって、今はAWS Lambda移行を進めているというか、これから始まるというか、まぁそんな状況です。
おわりに
なんだか無駄なことばっかりしているプライベート開発だったような気もしますが、こうして自分でいろいろ試してみるのは面白く、勉強になるとあらためて思いました。
AWS Lambda への移行でも、いろいろと学べる部分があると思うので今から楽しみです。
そんなわけで「がんばるぞいBot」の始まりから今後の未来まで書いてみました。 物語はこれからも続きます。
「今日も1日がんばるぞい!」