カンムでバンドルカードのバックエンドやインフラを担当している summerwind です。
バンドルカードではスマホ上で Visa のプリペイドカードを発行して決済に使える機能を提供しており、クレジットカード情報を扱っていることから、インフラの観点では高いセキュリティを維持することが重要になっています。バンドルカードのシステムは API や国際カードブランドと接続している決済システムなどの複数のコンポーネントで構成されていますが、システムが構築された時期によって構成や設定の方針などが異なるため、より高いセキュリティを達成するためにシステム構成の変更や整理、設定の見直しを日々進めています。
構成や設定の見直しを進めていく中で、全体的な方針や目指している姿を言語化しておいた方が周囲のエンジニアにも理解が得られやすいのではないかと感じたため、インフラに対する考え方や方針を言語化した「インフラマニフェスト」を定義することとしました。この記事では社内に公開しているマニフェストの一部を抜粋して紹介したいと思います。なお、日常的に AWS や GCP を活用されているエンジニアの方には当然の内容だと思われるかもしれませんが、今回は「あえて言語化する」ことを目的としているので、その点はご了承ください。
このインフラマニフェストではカンムのインフラを「こうしていくんや!」という方針的なものを言語化しています。 これは2021年のカンムのインフラの状況に基づいて定義されており、今後の改善などにより将来的には大きく方針が変更される可能性があります。
対象
このマニフェストが対象とする「インフラ」には以下が含まれます。
ワークロードとストレージを分離する
アプリケーションやバッチなどのワークロードとそのデータを保存するストレージは明確にリソースを分離し、ワークロードとデータが同居しない構成や設計を採用します。
例えば、Redash を動かすための EC2 インスタンスがあり、そこで Redash、Redis、PostgreSQL を実行していたとします。これらは以下のようにリソースを分離できます。
- Redash: ECS コンテナ (ワークロード)
- Redis: ElastiCache (ストレージ)
- PostgreSQL: RDS (ストレージ)
このように分離するのは、ワークロードは一般的に高速に動作しスケーラブルであることが求められ、また比較的短命であることに対し、ストレージは安定的に稼働し続けることが求められるなど、それぞれの要件が大きく異なるためです。複数の要件を達成しようとすると、どうしてもトレードオフが発生してしまい全ての要件を達成するのが困難になります。ワークロードとストレージを明確に分離すればそれぞれの役割における要件が達成しやすくなります。
なお、ストレージは一般的に運用負荷が高くなりがちなので、積極的にマネージドサービスを活用していきます。
ペットではなく家畜へ
ワークロードを実行するリソースは、ペットのように長時間稼働させて可愛がるのではなく、家畜のように使い捨てます。常に「私が死んでも代わりはいるもの」と言えるよう、デプロイのたびにリソースが入れ替わり続けるような状況を目指します。
これは、リソースを長時間稼働させればさせるほど、設定ドリフトが発生して設定や構成の変更がしにくくなったり、脆弱性の発見によりセキュリティが低下したりすることが背景にあります。長時間稼働により、設定ドリフトやセキュリティの低下に対応するための運用負荷も同時に高まっていきます。もしリソースを頻繁に使い捨てることが前提となっていれば、設定ドリフトは発生せず、最新のセキュリティを組み込むことも可能になり、アプリケーションやシステムの構成変更もしやすくなります。
ペットと家畜の話は以下の文書も参考してください。
メタデータで管理する
ワークロードやストレージなどの全てのリソースは名前のような一意の識別子に加え、メタデータを付与して管理します。
これは、インフラの運用ではリソースを様々な軸で集約して扱うシーンが多いためです。例えば、以下のようなシーンでは名前のような識別子だけでリソースを管理するには限界があります。集約したい軸ごとにメタデータを付与し、その値ごとに集約できると運用上の様々な課題を効率化できます。
リソースには次のようなメタデータを必ず付与し、項目単体あるいは複数の項目を組み合わせてリソースの管理を可能にします。またこのようなメタデータを付与できるサービスやツールなどを積極的に採用することとします。
メタデータ名 | 概要 |
---|---|
環境 | リソースがどの環境用 (本番環境、ステージング環境など) のものなのかを示す |
サービス | どのサービスあるいはプロダクトに属しているかを示す |
役割 | サービスの中での役割を示す (API、管理ツールなど) |
データにより宣言的に管理する
全てのリソースの設定や状態はデータファイルに構造化データとして定義し、専用のツールを使用してその定義内容を実際のリソースと一致させることで管理します。構造化データには JSON、YAML、HCL2 形式のいずれかを採用し、それらの形式でリソースを宣言的できるツールを積極的に採用します。
これまで一般的なインフラのリソースの多くは手順書などの「命令的」な定義により管理されてきましたが、これは順序に依存する仕組みであり、手順の変更などによって設定を再現できなくなったりする問題があります。古いドキュメントの手順に従って作業を実施したら環境を再現できなかったという経験がある方は多いのではないでしょうか。
この問題を解決するために、手順ではなく以下のようなデータファイルにリソースのあるべき状態を定義し、その定義に基づいてリソースの状態を一致させるツールを積極的に採用します。この例では ECS クラスター prd
がメタデータ付与された状態である、ということを Terraform 向けの HCL2 形式で定義しています。これらのデータファイルは Git などで管理することにより、変更のレビューやテスト、特定時点のリソースにロールバックする、といったことが可能になります。
resource "aws_ecs_cluster" "prd" { name = "prd" tags = { Name = "prd" Service = "A" Environment = "prd" } }
なお、ここではクラウドサービスのリソース管理を例に挙げましたが、Linux などのインスタンスのシステム構成や、ルーター機器の設定などについても同様に可能な限り宣言的にデータファイルで管理します。
継続的にテストをする
インフラのリソースをデータとして宣言的に定義すると、次のようなテストが可能になります。これらのテストは CI サービスを利用して、バージョン管理システムに変更を追加する毎に実行し、レビュー時にはその検証結果が妥当なものであるかを評価します。
- ツールを使用して定義の内容とリソースの実際の設定の差分を検証する
- ポリシーツールを使用して、意図しない設定の定義が含まれていないかを検証する
これらのテストを継続的に実行することで、意図しない変更に早期に気付けたり、データファイル以外で発生した設定ドリフトを検出できるようになります。
本番環境、ステージング環境、開発環境を使い分ける
リソースは本番環境、ステージング環境、開発環境の3つの環境に用意して使い分けます。使用する環境とその用途は次の通りです。ステージング環境は本番環境と同等の環境として維持し、リリース前の最終的な動作確認や検証にのみ使用します。レビューを受けていない開発中のコードなどは開発環境に対してのみデプロイします。
環境名 | 用途 |
---|---|
本番環境 | 利用者にサービスを提供するための環境 |
ステージング環境 | 本番環境と同じ構成でテストを実行するための環境であり、リリース用のコードのみをデプロイする |
開発環境 | 開発中のコードの動作を検証するための環境であり、開発中のコードをデプロイする |
これらの環境は全て独立したものとして管理し、各環境のリソースが他の環境のリソースに影響しないようにします。また、AWS などのクラウドプロバイダーについては、環境ごとにアカウントを分離します。
シンプルにする
リソースの構成は可能な限りシンプルにします。リソースが少なければ少ないほど運用上の負荷が減るため、少人数で開発と運用をしているカンムにおいてシンプルさを選択することはとても重要だと考えます。具体的には次のような選択をします。
いかがでしたでしょうか。社内のマニフェストにはより多くの項目について記載していますが、ここでは紹介しきれないのでまた機会を見つけてご紹介したいと思います。
カンムではセキュアでモダンなクレジットカード決済インフラを作りたいエンジニアを積極的に採用しています!