複数のサービスをリソース増強せずに運用する方法

CELTFの競技サイトを運営していく上で、できる限り低リソースかつ複数のサイトを運用する必要があったので、採用した方法を紹介します。
安定して本番運用するというよりは、立ち上げ当初の小さいサービスを幅広く運営するケースを想定しています。

目的

  • 定額で複数のサービスを運用する
    • 定額で収めるために、App Engineなどは利用せずVPSで完結するようにします。
  • サービス数によって必要メモリを増加させない
    • サービス数の増加によりリソースを増強させないため、できる限りメモリはサービス数に依存させないようにします。

システム構成

サービス数によってメモリを増加させないために、できる限りリソースを使いまわせるようにします。
また、別々のサービスを運用するためにドメインで切り分けられるようにします。

構成図

FastAPI

サービスごとにNamespaceを作成し、サービス名をプリフィックスに指定してルーティングします。

Nginx

サービスごとにServer(VirtualHost)を作成します。
ルートロケーションはスタティックファイルが保存されているパスに向け、APIロケーションはFastAPIにプロキシします。
FastAPIへのプロキシはドメイン毎にNamespaceを振り分けて転送します。

構成ファイル

Nginx

Service-AとService-Bのサーバを作成します。
すべてのファイル構成はGitHubを確認してください。

server {
    listen 80;
    server_name service-a.localhost;

    access_log off;

    location /api/ {
        proxy_pass http://api/service-a/;
    }

    location / {
        root   /usr/share/nginx/html/service-a;
        index  index.html;
    }
}

server {
    listen 80;
    server_name service-b.localhost;

    access_log off;

    location /api/ {
        proxy_pass http://api/service-b/;
    }

    location / {
        root   /usr/share/nginx/html/service-b;
        index  index.html;
    }
}

FastAPI

APIRouterを使用し、サービスごとにルーティングを行います。
すべてのファイル構成はGitHubを確認してください。

from fastapi import FastAPI

import service_a

import service_b

app = FastAPI()

app.include_router(service_a.router, prefix="/service-a")
app.include_router(service_b.router, prefix="/service-b")

実演

実際に動作させ、リクエストを送ってみます。

Service-Aへのリクエスト

ブラウザを利用し、Service-Aへリクエストしてみます。

Vue.jsで作成されたスタティックファイルが表示されたので、次はAPIにcurlでリクエストしてみます。

fealone$curl http://service-a.localhost/api/
"Hello World with Service A"

APIへのリクエストも正常に行う事ができました。

Service-Bへのリクエスト

ブラウザを利用し、Service-Bへリクエストしてみます。

Vue.jsで作成されたスタティックファイルが表示されたので、次はAPIにcurlでリクエストしてみます。

fealone$curl http://service-b.localhost/api/
"Hello World with Service B"

Service-Bに対しても、正常にリクエストを行う事ができました。

おわりに

今回はHTTPSの設定をしていませんが、Let's Encryptなどを利用してサーバ毎に証明書を作成する事でHTTPS化も可能です。
コードはGitHub上にアップロードしているので、参考にしてみてください。

fealone/multiple-services-with-virtualhost
Manage multiple services with a virtual host to doesn't resource size depends on the number of services. - fealone/multiple-services-with-virtualhost

当たるかどうかわからないサービスを複数作成し、定額かつ共有リソースで運営したいときにおすすめです。