Upgrade to Pro — share decks privately, control downloads, hide ads and more …

15年以上動くECシステムをクラウドネイティブにするためにやっていること

Takuya TAKAHASHI
December 09, 2021
1.9k

 15年以上動くECシステムをクラウドネイティブにするためにやっていること

2021/12/09のペパボテックカンファレンスで発表した内容です。

Takuya TAKAHASHI

December 09, 2021
Tweet

Transcript

  1. 4 自己紹介 技術部 技術基盤チーム 2019年 中途入社 高橋 拓也 Takahashi Takuya

    インフラエンジニア (プライベート|ハイブリッド)クラウドのあれこれや サービスの可用性を上げること全般を担当 • Twitter : @takutaka1220 • GitHub: takutakahashi
  2. 5 カラーミーショップの可用性における課題 • 障害が発生すると... ◦ お客様の利益を奪ってしまう ◦ サービスのプレゼンスを損なってしまう ◦ CS

    の方々の顧客対応の時間を増やしてしまう ◦ エンジニアの工数を奪ってしまう ◦ なぜ守ってあげられなかったんだ... と夜も眠れなくなる ◦ またなにか障害が起こってしまうのでは... と夜も眠れなくなる 障害っていやですよね
  3. 6 カラーミーショップの可用性における課題 • お客様に影響の出ない範囲での障害 ◦ プラットフォームのハイパーバイザ故障によるインスタンス数の低下 ◦ ログパーサが失敗しログ集約サーバへの転送ができなくなる • 全ショップが閲覧不可となる障害例

    ◦ ショップ閲覧/決済サービスが何らかの原因により全インスタンス利用不可能になる ◦ LB (HAProxy が動くインスタンス) が何らかの原因により利用不可能となる 大小さまざまな障害がある
  4. 7 カラーミーショップの可用性における課題 • 障害への備えは考えうる限り万全に実施している ◦ CI によるテスト自動化 ◦ 監視、アラート設定、オンコールの実施 ◦

    可用性に関する取り組みの強化 ▪ アプリケーションレイヤでの取り組み強化 • 前半のお話をご覧ください ▪ インフラ、アーキテクチャレイヤの取り組み強化 • 私達の取り組みはこちら 障害への対策
  5. 8 カラーミーショップの可用性における課題 • 障害への備えは考えうる限り万全に実施している ◦ CI によるテスト自動化 ◦ 監視、アラート設定、オンコールの実施 ◦

    可用性に関する取り組みの強化 ▪ アプリケーションレイヤでの取り組み強化 • 前半のお話をご覧ください ▪ インフラ、アーキテクチャレイヤの取り組み強化 • 私達の取り組みはこちら 障害への対策 アプリケーションレイヤでの取り組みにより 障害の種が少しずつ取り除かれている
  6. 9 カラーミーショップの可用性における課題 • 障害への備えは考えうる限り万全に実施している ◦ CI によるテスト自動化 ◦ 監視、アラート設定、オンコールの実施 ◦

    可用性に関する取り組みの強化 ▪ アプリケーションレイヤでの取り組み強化 • 前半のお話をご覧ください ▪ インフラ、アーキテクチャレイヤの取り組み強化 • 私達の取り組みはこちら 障害への対策 どんな障害が発生しても早急に復旧できる環境を整備する必要がある これがインフラで 解決したい課題
  7. 10 カラーミーショップの可用性における課題 • 障害の影響度 = 発生ポイントの重要度 * 障害発生率 * 影響範囲

    * 復旧時間 • 発生ポイントはハンドリング不能と仮定する • 障害発生率はアプリケーションレイヤでの施策が進行中 • インフラでは、影響範囲を狭く、復旧時間を短くすることで影響度を最小化する 予測不可能な障害への対応策
  8. 11 カラーミーショップの可用性における課題 • 障害の影響度 = 発生ポイントの重要度 * 障害発生率 * 影響範囲

    * 復旧時間 • 発生ポイントはハンドリング不能と仮定する • 障害発生率はアプリケーションレイヤでの施策が進行中 • インフラでは、影響範囲を狭く、復旧時間を短くすることで影響度を最小化する 予測不可能な障害への対応策 目的達成のために、 ShopSet という仕組みを作って運用することにした
  9. 15 カラーミーショップの可用性における課題 • 商品閲覧から購入に関わる全システムを Kubernetes (k8s) 上に構築 • 全システムのまとまりを ShopSet

    と名付ける • Operator により ShopSet の構築コストを限りなくゼロにする ShopSetについて軽く説明
  10. 16 カラーミーショップの可用性における課題 • k8s 上に ShopSet を管理してくれる Operator をデプロイする •

    Operator は ShopSet リソースを解釈し適切なリソース群をデプロイする • 人間は ShopSet リソースをデプロイするだけで全ての管理が完結するようになる Operator により ShopSet の構築コストを限りなくゼロにする k8s operator shop cart proxy shopset watch deploy api
  11. 17 カラーミーショップの可用性における課題 • 商品閲覧から購入に関わる全システムを k8s 上に構築 ◦ カラーミーショップはショップ閲覧、カート機能など複数のシステムに分かれている • 全システムのまとまりを

    ShopSet と名付ける • Operator により ShopSet の構築コストを限りなくゼロにする ShopSetについて軽く説明 ShopSet の実現のためには、 Operator の存在が不可欠 カラーミーショップを k8s に載せていくぞ!
  12. 20 カラーミーショップを k8s で動かすために必要なことは? • 現行システムは仮想マシン (VM) で動いている • VM

    と同じ考え方を k8s に持っていくと良くないことが起こる ◦ コンテナには ssh できない! ◦ IP がコロコロ変わる! ◦ プロセスが死ぬことは当たり前! ◦ etc... k8s で動かすことがゴールではない k8s で動作させるメリットを最大限享受できる アプリケーション構成に変更する必要がある
  13. 21 カラーミーショップを k8s で動かすために必要なことは? • そもそも k8s で良く動かすためには ◦ システムは互いに素結合であり、Service

    Discovery で相互に参照する ◦ システムはイミュータブルである ◦ 不必要なステートを排除し、データはマネージドサービスで持つ ◦ システムをいかなるタイミングでも作成、削除されることができる状態に保つ • 上記の構成を運用しやすい状態に保ち続ける ◦ 障害発生時にはどこで障害が発生したのか切り分けられる ◦ 監視やアラートを設定できる どういう構成を追い求めるべき?
  14. 22 カラーミーショップを k8s で動かすために必要なことは? • そもそも k8s で良く動かすためには ◦ システムは互いに素結合であり、Service

    Discovery で相互に参照する ◦ システムはイミュータブルである ◦ 不必要なステートを排除し、データはマネージドサービスで持つ ◦ システムをいかなるタイミングでも作成、削除されることができる状態に保つ • 上記の構成を運用しやすい状態に保ち続ける ◦ 障害発生時にはどこで障害が発生したのか切り分けられる ◦ 監視やアラートを設定できる どういう構成を追い求めるべき? これはつまり、クラウドネイティブであるということ
  15. 25 カラーミーショップを k8s で動かすためにやったこと • 個別のシステムに以下の変更を加えている (一部抜粋) ◦ ステートフルからステートレスのアーキテクチャへの変更 ▪

    消失して困るファイル(データ、ログ、キャッシュ) をコンテナ内に持たない ◦ 固定 IP (inbound, outbound) を期待する実装の削除 ▪ リクエストを(送る|受ける)クラスタは無限に増える ◦ 環境変数とテンプレートエンジンを用いた環境切り替え ▪ env (production, staging) の関心をコードからなくす k8s にデプロイされるシステムへの変更
  16. 26 カラーミーショップを k8s で動かすためにやったこと • 個別のシステムに以下の変更を加えている ◦ ステートフルからステートレスのアーキテクチャへの変更 ▪ 消失して困るファイル(データ、ログ、キャッシュ)

    をコンテナ内に持たない ◦ 固定 IP (inbound, outbound) を期待する実装の削除 ▪ リクエストを(送る|受ける)クラスタは無限に増える ◦ 環境変数とテンプレートエンジンを用いた環境切り替え ▪ env (production, staging) の関心をコードからなくす k8s にデプロイされるシステムへの変更 詳しい施策内容を一部抜粋して 解説します
  17. 28 自己紹介 技術部プラットフォームグループ 2018年 中途入社 菅原 千晶 Sugawara Chiaki 2018年にWeb業界未経験でペパボカレッジ6期とし

    てメーカー系SEから現職。 カラーミーショップ担当SREとして運用改善やk8s 導入・CI/CD pipeline整備などを経験。 @ch1aki @ch11aki
  18. 29 複雑なミドルウェアをコンテナ化するためのコンテナイメージ振る舞いテスト • カラーミーショップのリバースプロキ シ(Nginx)は複雑 ◦ 1万件以上の独自ドメインのTLS終端 ▪ ngx_mrubyで証明書管理API、Redis から動的に証明書取得

    ◦ 複数ロールへプロキシ ▪ 複数のアプリケーションロール ▪ オプションでロリポップ!MCなど ◦ ロールによってヘッダの変更や ngx_mrubyでCookieをフィルタ ◦ rate limit等 複数のアクセス制限機能 背景(1/2) 証明書API
 ショップ ページ カート API ロリポップ! マネージドクラウド 外部サイト . . . コンテナ化 request 動的証明書 応答
  19. 30 複雑なミドルウェアをコンテナ化するためのコンテナイメージ振る舞いテスト • 並行稼働しながら緩やかに新アーキテクチャに移行するため、コンテナ化の際には 既存のミドルウェア設計を踏襲する方針を選択 • コンテナ化の際のテスト項目が膨大&環境用意が面倒 ◦ 設定可能な数十個の環境変数 ◦

    正常系に加え一部ロールの障害時に意図したフォールバックの挙動のテストのため、複数 パターンの構成でコンテナを起動 ◦ よくあるミス:環境変数名ミス、テンプレート記法ミス、ファイルの配置漏れ、etc... 複数パターンの構成で、コンテナイメージと依存ロールを起動しリクエストを実行して 想定通りの挙動をするかを楽にテストしたい 背景(2/2)
  20. 31 複雑なミドルウェアをコンテナ化するためのコンテナイメージ振る舞いテスト • infrataster ◦ サーバーの振る舞いテストツール ◦ 振る舞いのテストに止まり目的に合わない&更新が止まっている? • container-structure-test

    ◦ コンテナイメージの構造をテストするためのツール ◦ 単体のイメージのテストに止まるため目的に合わない • Testcontainers ◦ 統合テスト向けにコンテナを簡単に操作可能な複数言語で実装があるライブラリ ◦ 利用目的が異なるため、作成したコンテナに対するテストコードが冗長になりがち 既存のソリューションを調査
  21. 32 複雑なミドルウェアをコンテナ化するためのコンテナイメージ振る舞いテスト • Cybozu Inside Out, 複雑怪奇な nginx を Go

    と Docker でユニットテストする ◦ https://blog.cybozu.io/entry/2020/04/16/080000 ◦ nginxをユニットテストするためにDockerとGoを利用 ◦ testerコンテナ内でGoのテストを実行、nginxの設定をマウントしたコンテナ を作成、自身がmockサーバーになりテストを実行 →既存のソリューションで課題をすべて解決してくれるものはなかったが、やりた いことに一番近そう これを参考に汎用的なコンテナイメージの振る舞いテストツールを作ることにした 最終的に参考にしたもの
  22. 33 複雑なミドルウェアをコンテナ化するためのコンテナイメージ振る舞いテスト • テストの基本的なアーキテクチャは参考元(※)を踏襲 • nginxに限らず様々なプロジェクトで利用できるように、 ◦ go package化 ◦

    任意のimage tag、任意の環境変数を設定可能 • http mock server作成機能に加え、redis mock server作成などを追加 • テスト対象コンテナへのhttpリクエストの実行をアサーションメソッドとして実装 containertester(仮) ※ https://blog.cybozu.io/entry/2020/04/16/080000
  23. 34 複雑なミドルウェアをコンテナ化するためのコンテナイメージ振る舞いテスト 1. Mockサーバーを起動 2. 任意の設定でコンテナを起動 3. 起動したコンテナに対してhttpリク エストを実行し結果を検証 以上のテストがこれだけのコードで実現

    containertester(仮)サンプルコード func TestReverseProxy(t *testing.T) { app := tester.StartMockAP(t, tester.MockApResponseBody("app server")) defer app.Close(t) nginx := tester.StartContainer(t, tester.ContainerConfig{ Image: "nginx-proxy:test", Environment: map[string]string { "APP_SERVER": app.Host(), }, }) defer nginx.Close(t) nginx.AssertHttpGet(t, tester.ExpectedBody("app server")) }
  24. 37 自己紹介 EC事業部 カラーミーショップグループ アプリストアチーム 2019年 中途入社 神﨑 拓人 Kanzaki

    Takuto アプリストアチームとしての活動の傍ら可用性向上 プロジェクトとして主に既存アプリケーションの Kubernetes化を担当。 @windyakin @MITLicense
  25. 39 レガシーなアーキテクチャをKubernetes上で活かすために • Kubernetes 上での最小アプリケーション動作単位「Pod」 ◦ 単体・複数のコンテナを寄せ集めて動作させている • Pod は割とカジュアルに作成・削除される

    ◦ Docker イメージを差し替えたいとき(アプリケーションのアップデート) ◦ Pod の台数を増やす・減らすとき(スケールアップ・ダウン) • Pod の再作成が行われるとDockerイメージに含まれるファイル以外は消える ◦ キャッシュファイルは Pod が立ち上がっている間だけ維持される ◦ 再作成後はキャッシュファイルがクリアされてしまう KubernetesでのPodのライフサイクルとファイルキャッシュは相性がよくない
  26. 40 レガシーなアーキテクチャをKubernetes上で活かすために • 当初は「対応しなくてもそんなに影響ないのでは?」説が出ていた ◦ Pod が再作成されても Pod にアクセスがあれば徐々に溜まっていく ◦

    一方で Virtual Machine ではたまり続けるキャッシュに対する課題もあった • キャッシュがない状態になるとどれぐらい影響があるのか計測することに ◦ キャッシュがない Virtual Machine を新たに用意して本番に投入しメトリクスを取得 k8s に移行した時に影響が出やすいと判断しキャッシュを活かす方法を模索することに キャッシュのライフサイクルの変更によってどれほどの影響が出るかを調査 • 他VMより20〜30%ほど遅い • これが30〜40分ほど続く
  27. 41 レガシーなアーキテクチャをKubernetes上で活かすために 1. k8s の機能 Persistent Volume(永続ボリューム) により解決する案 ◦ 大容量ストレージを持った

    Node 上にて永続ボリュームをマウントする ◦ それまで立ち上げていたPodの数を超えて作成すると結局キャッシュがない状態になる → スケジューリングによる性能劣化など新たな懸念材料などが生まれてしまう 2. キャッシュファイルをオンラインストレージでホストする案 ◦ Pod にあるキャッシュファイルを定期的にオンラインストレージにアップロード ◦ Pod の起動時にキャッシュをオンラインストレージからダウンロードしてくる → これを実現するアプリケーションを実装をすることに ファイルキャッシュをk8s上で保持するのためのアプローチ
  28. 42 レガシーなアーキテクチャをKubernetes上で活かすために • BigQuery からアクセスが多いショップを割り出す • アクセス上位のキャッシュを Amazon S3 にアップロードしていく

    • Pod の起動時に Init Container で Amazon S3 にあるキャッシュを落としてくる キャッシュマネージャアプリケーションの作成とリリース