最初、どこから作りはじめたかについて話します。
技術者向けに書いていますので、非エンジニアの方は、飛ばしながら読んで頂ければと思います。
【失敗談】AWSでとりあえず作ってみようからスタート
後にわかりますが、この実装は後に全てなくなります。(笑)
動的にコンテナを起動させるシステムを実装するので、まずは、Docker
に関する調査から始まりました。
Docker はデフォルトでは UNIXソケット
を利用して操作を可能にしますが、 TCPソケット
も利用できることがわかりました。
よって、コンテナを起動するためのサーバーを立て、そこにコンテナの起動や終了のリクエストを出すことで遠隔からコンテナ操作を可能にすることを考えました。
構成図は以下の通りです。
以下の3つの機能が必要です。
- Webアプリケーション = EC2
- Dokcerコンテナを起動・停止するAPI(docker-manager) = EC2
- Dockerコンテナを動作させるサーバー群 (コンテナサーバー) = EC2
ユーザーからのアクセスを通常のWebアプリケーションで受け、その後コンテナオーケストレーションシステムの下位互換のような API
を実装し、API経由で コンテナが立ち上がるサーバー(以後、コンテナサーバー)
上でDockerコンテナを起動する構成を考えました。
docker-manager
の役割は、docker-compose
コマンドとほぼ同じで、コンテナ起動の設定ファイルを読み込み、それに応じたユーザごとの専用コンテナを作ることです。しかし、docker-compose
はAPIとして用意されているわけではないので、自分達で書く必要がありました。
ユーザーは コンテナサーバー
の Global IP
を利用して各コンテナにアクセスすることを想定していました。そのため、ユーザごとに踏み台コンテナを作成し、ユーザごとに別々のポートを介してコンテナにアクセスさせようと考えました。
【失敗談】プログラミング言語はなんでもよくない
早速、Pythonを利用してオリジナルの docker-manager
を作成しました。
Pythonを利用した理由は、
- Pythonになれていたという超絶安易な理由
- Dockerのクライアントライブラリが便利そうという希望的観測
ちなみに当時は、人に誇れるほどのWebやAPIの開発経験はなく、大学の研究のためにPythonで少しプログラムを書いたり、CTFを解くために必要なプログラムをかける程度の能力でした。
そこで、REST API
なるものをググって、いい感じに実装をはじめました。(いい感じってなんだよ。)
重量級フレームワークである必要はなかったので、 Flask
を選定しました。
【成功談】アーキテクティングって大事。システム構成図とプログラミング言語の変更
2週間ほどである程度動くものができたのですが、完成した後に問題が発生しました。
それは、「なんか遅い」ということです。遅い原因としては、以下の2つだと結論づけました。
- コンテナサーバーの起動が遅い
- プログラムが遅い
そもそもコンテナが起動するだけのサーバーに、EC2のようなサーバーが必要なのか?という疑問から、コンテナ起動に特化したOSがないかを調査したところ、GCPにCOS(Container Optimized OS)があることを発見しました。
また、Docker自体がGoで書かれていること、Pythonより早いということからGoの方が相性が良いと判断し、Goに切り替えました。
さらには、APIはサーバーレスに移行しました。
まとめると、以下のようになります。
変更前 | 変更後 |
---|---|
AWS | GCP |
EC2(Amazon Linux) | GCE(Container Optimized OS) |
APIサーバー | サーバーレスなAPI |
Python Flask | Go Echo |
結果として、体感5秒以上のタイムロスを実現でき、ワンクリック5秒で環境を起動できるようになりました。
この時のサービス全体のアーキテクチャー図はこちらです。後に、このアーキテクチャー図はもう少し変更が入ります。