50 ポイント 投稿者 xguru 2021-04-12 | 11件のコメント | WhatsAppで共有
  • ストレスなく、ゆっくりSaaSを運営する1人開発者のアーキテクチャ説明

  • 複数のプロジェクトを同時に運営するためのインフラを構築している

  • 自身が最近作ったPanelBearというSaaSを基準に説明
    → 最小のVPSでSQLite + Djangoから開始
    → 6か月のイテレーションを通じて、EKS上でDjangoモノリス + Postgres + ClickHouse(分析)+ Redis(キャッシュ)+ Celery(定期ジョブ)
    → ほとんどを自動化:オートスケーリング、ingress、TLS証明書、フェイルオーバー、ロギング、モニタリングなど
    → この設定を複数のプロジェクトで使っているため、コストを下げつつ実験を本当に簡単に始められる
    → インフラ管理にはほとんど時間がかからない(月0〜2時間)
    → ほとんどの時間を機能開発、顧客支援、ビジネス成長に使える

  • AWSでKubernetesを使っているが、必須というわけではない。ただ、本人は慣れているので安定運用できると考えている
    → 忍耐強いチーム(エラーに一緒に耐えて防いでくれる)でこのツールを数年間使いながら学んだ
    → 「Kubernetesは単純なものを複雑にするが、複雑なものを単純にもする」

  • 自動DNS、SSL、およびロードバランシング
    → CloudFlare ProxyからAWS L4 NLB(Network Load Balancer)へすべてのトラフィックを転送
    → Requestが入るとLBがk8sクラスターノードの1つへフォワード
    → これらのノードは複数のAZ(Availability Zone)にまたがるプライベートサブネット内にある
    → k8sがリクエスト先のサービスを見つけるのはingress-nginx(Nginxクラスター)が担当
    → nginxがトラフィック転送前にRateLimitingおよびトラフィックシェーピング規則を適用
    → PanelBearではアプリコンテナはUvicornで配信されるDjango
    → Terraform/K8s間にいくつかの設定ファイルがあり、それをほとんどのプロジェクトで共有
    → 新規プロジェクトのデプロイは20行程度のingress設定で可能

  • 自動ロールアウトおよびロールバック
    → masterにpushするたびにGitHub ActionsでCIパイプラインを実行
    → コードベースを検査し、Docker-Composeで完全な環境を作ってE-to-Eテスト
    → 検査を通過するとECR(AWSのDocker Registry)へpushされる新しいDockerイメージをビルド
    → k8sクラスター上のfluxコンポーネント( https://fluxcd.io/ )がクラスター内イメージを自動同期
    → Fluxが自動でIncremental Rolloutを実行

  • Horizontal Autoscaling
    → CPU/メモリ使用量ベースでオートスケーリング
    → クラスターの各ノードにPodが多すぎる場合、自動でサーバーを追加してクラスター容量を増やし負荷を下げる。仕事がないときは縮小
    → PanelBearではAPI Podのレプリカ数を2〜8の間で自動調整

  • CDNを使ったStatic Assetキャッシュ
    → CloudFlareをDNSに設定し、すべてのリクエスト処理とDDoS防御まで担当
    → Staticファイル配信にはWhitenoise( https://github.com/evansd/whitenoise )を使い、NGinx/Cloudfront/S3へファイルをアップロードする必要がない
    → PanelBearのランディングページのようないくつかの静的WebサイトにはNextJSを使用

  • アプリケーションデータキャッシュ
    → 一部ではPythonが提供するインメモリLRUキャッシュを使用
    → ほとんどのエンドポイントではクラスター内Redisを使用

  • EndPointごとのRate Limiting
    → nginx-ingressでグローバルなレート制限をしているが、時にはエンドポイント/メソッド単位で個別の制限が必要
    → Django Ratelimitライブラリを使ってDjangoビューごとの制限を宣言可能
    → Redisをバックエンドに使い、各エンドポイントへリクエストするクライアントを追跡するよう構成(IPではなくクライアントキー基盤のハッシュ)

  • App Administration
    → DjangoのAdmin Panelが標準でデータ閲覧・編集機能を提供
    → 不審なアカウントへのアクセス遮断 / 告知メール送信 / アカウント削除要求の処理などの機能を追加(最初はソフト削除し、72時間以内に完全削除)

  • 定期ジョブの実行
    → SaaSではさまざまな定期ジョブが動作:顧客向けの日次レポート、15分ごとの利用統計計算、従業員向け指標メールなど
    → いくつかのCeleryワーカーとCelery beatスケジューラをクラスター内で実行中。Redisをタスクキューとして使用
    → 定期ジョブが正しく実行されないときにSMS/Slack/Emailなどで通知を受けるためHealthChecks.ioを使用

  • App Configuration
    → すべての設定は環境変数を利用。古典的だが移植性が高く広くサポートされている

  • Keeping Secrets
    → kubesealを利用。非対称暗号化を使ってSecretを暗号化し、復号鍵へアクセス権のあるクラスターだけが復号可能
    → クラスター内のSecretを保護するためにAWS KMSの暗号鍵を利用

  • リレーショナルデータ:Postgres
    → 実験用にはクラスター内でバニラPostgresコンテナを運用し、K8s CronjobでS3へ毎日バックアップ
    → プロジェクトが成長したらデータベースをクラスター内からRDSへ移し、AWSに暗号化バックアップやセキュリティアップデートなどを任せる
    → セキュリティ強化のため、AWSのDBはPrivate Networkからのみアクセス可能

  • カラム型データ:ClickHouse
    → PanelBearの分析データを効率よく保存しリアルタイムにクエリするためClickHouseを使用
    → 優れたColumnarデータベースで、非常に高速かつ設計が適切なら高い圧縮率を示す(ストレージ削減 = 収益増加)
    → K8sクラスター内でClickHouseインスタンスをセルフホスト
    → S3へColumnarデータを定期バックアップするCronJobを作成
    → 障害時にS3からデータを手動バックアップ・復元するためのいくつかのスクリプト

  • DNSベースのサービスディスカバリ
    → K8sがクラスター内DNSレコードを自動管理し、トラフィックを該当サービスへルーティング
    → オートスケーリング中でも健全なpodに接続されるよう自動でDNSレコードを同期

  • Version-Controlled Infrastructure
    → Docker、Terraform、K8s manifestを単一リポジトリ(Infra Mono-Repo)で管理
    → 簡単なコマンドでインフラの作成・削除が可能で、バージョン管理により再現性も確保

  • Cloud Resource向けTerraform
    → ほとんどのクラウドリソースはTerraformで管理
    → これによりインフラ資源と設定を文書化し追跡可能

  • Appデプロイ向けK8s manifest
    → インフラモノレポのYAMLファイルにK8s Manifestを記述
    clusterappsの2つのフォルダに分割
    clusterにはnginx-ingress、暗号化されたsecret、Prometheusスクレイパーのようなクラスター全体サービス関連の設定を含む
    appsにはプロジェクトごとに1つのnamespaceへ情報を保存

  • サブスクリプションと決済
    → Stripe Checkoutを使ってすべての決済を処理
    → 決済情報そのものに関与する必要がなく、製品に集中できる
    → 顧客セッションを作成してStripeのページへリダイレクトし、その後Webhookで結果を受け取れば完了

  • Logging
    → ロギングエージェントを使わず、単純にstdoutへログ出力すればk8sが自動でログ収集とrotateを実行
    → FluentBitなどを通じてElasticsearch/Kibanaなどへ送ることもできるが、シンプルさを保つためまだしていない
    → ログ確認にはCLIツールのsternを使用

  • モニタリングとアラート
    → 当初はPrometheus / Grafanaをセルフホストしていたが、クラスター障害時にアラートシステムも一緒に停止して不便だった
    → そこでNew Relicへ変更
    → すべてのサービスには指標を自動収集しDatadog、New Relic、Grafana Cloudなどへ送れるPrometheus Integrationがあり、New Relicへの移行も彼らが提供するPrometheus Dockerイメージを使うだけで可能

  • エラー追跡
    → Sentryを使ってアプリケーションエラーを収集
    → Slackの#alertsチャンネルを使って、downtime、cron job failures、security alerts、performance regressions、application exceptionsなどすべての警告を一元化

  • Profilingとその他の良いもの
    → 深い分析が必要なときはcProfileやsnakevizのようなツールを使用
    → ローカルマシンではDjango Debug Toolbarを利用

11件のコメント

 
wellsbabo 2024-08-13

ありがとうございます

 
admin2 2021-04-13

SentryとNew Relicの機能差はかなりありますか?

似たような機能をすると考えていましたが、まだ使ったことがないので。

 
kbumsik 2021-04-13

おお、うちの会社でもk8s導入を検討中なのですが、1人スタートアップでなくてもかなり参考になる良い記事ですね。

 
fortune 2021-04-12

良い文章をありがとうございます。刺激を受けました。

 
khris 2021-04-12

必ずしも一人スタートアップでなくても、良い文章ですね

 
yshrust 2021-04-12

ちょっとした誤字ですが、、

  • エラー追跡

→ Sentry を使ってアプリケーションエラーを収集

=> 収集 のことだと思います

 
xguru 2021-04-12

ありがとうございます。修正しました〜!

 
xguru 2021-04-12

日本国内でも、自分のサービスで収益を上げる個人開発者や小規模チームがもっと増えてほしいと思っています。

ここGeekNewsが、そうしたサービスが自らを知らせ、健全なフィードバックを受け取る場として成長してくれたらうれしいです。

 
wellsbabo 2024-08-13

ありがとうございます

 
reedids 2021-04-12

同意します。ありがとうございます :)

 
e1q88 2021-04-12

👍