自己紹介

高橋拓也氏(以下、高橋):それでは「カラーミーショップの可用性向上のためのインフラ刷新」と題して、GMOペパボの高橋拓也が発表します。よろしくお願いします。本日のアジェンダはこうなっています。課題とその解決方法みたいなところと、今を話そうと思っています。

まず、簡単に自己紹介をさせてください。高橋拓也と言います。GMOペパボでインフラエンジニアをやっています。GMOペパボではあだ名で呼び合う文化があり、僕はtakutakaと呼ばれています。

これが今回のセッションで一番大事なところですが、僕は自宅サーバーをたくさん飼っていて、構成がこんな感じです。k8s masterをラズパイで立てています。10G Switchが、今の僕の自慢です。

2番目に大事な、カラーミーショップの話を進めたいと思います。カラーミーショップを知らない方のために軽く説明します。カラーミーショップはGMOペパボが運営する、ネットショップを簡単に作成して運営できるサービスです。

解決したい課題

それでは、解決したい課題について説明します。昨今の巣ごもり需要により、ECの需要が非常に増加傾向にあります。ありがたいことにカラーミーショップ上のショップオーナーさんの中でも、大量に売り上げが増えたショップも多くなってきました。

ということは何が起こるかというと、システムへの負荷がものすごく高まってきている現状です。

その予告を打ったタイミングでバーっと人が集まってきて、サービスがデグレ(デグレーション)ってしまったり。人気商品に対して、botを使ったDDoS(Distributed Denial Of Service)に近いアクセスも頻繁に起こるようになってきて、今困っている状態です。

カラーミーショップはマルチテナント型アーキテクチャを採用していて、すべてのショップアクセスが同じサーバーを通る構成になっています。

ということは、DDoSを受けたりする人気ショップの負荷が、ほかの負荷を受けていないショップに対しても波及して、サービス全体がダウンするような状態が起きてしまいました。

さらに昨今の巣ごもり需要の増加により、事業規模が大きくなってきました。ショップオーナーさんもECに対する期待値が非常に高まってきているので、とにかくシステムの安定性をさらに向上させる施策が必要になってきました。

可用性向上への道

そこでカラーミーショップが打った、可用性向上への道を紹介します。最初の試作は分離環境でした。とある大量販売で、サービスダウンが頻発してしまったタイミングがあり、そのときに既存のシステムのまったく同じ構成のクローンを構築してみました。それが現在社内で“分離環境”と呼ばれているものです。

大量販売の対象ショップのみ分離環境に向き先を変更して、ほかのショップのリクエストを守る施策を実施しました。

こちらは非常に効果的にワークして、大量販売による全体のダウンを、ある程度防げるようになりました。現在でも大量販売などが行われる際は、分離環境に向けるオペレーションを実施してます。

ShopSetアーキテクチャでほかの課題も解決できるか

この分離環境を応用して、多くの課題を解決できるのではと考えました。ゼロコストで分離環境を作成して、高トラフィック対策以外でもその環境を利用する。これが今回の可用性向上の方針です。

分離環境改め、ShopSetアーキテクチャと名前をつけてやっています。ShopSetは僕らが名前をつけたもので、ユーザーが決済完了までで通るコンポーネントをまとめた、ひとかたまりのことを指します。複数ショップの集合体だから、ShopのSetでShopSet。安直です。まあ、僕がつけたんですが。

1つ以上のShopSetで冗長構成をとることを目指したり、そのShopSetを、それぞれAWSやオンプレ(オンプレミス)の環境に載せて、プラットフォーム冗長を実現したりする構成を目指しています。

このような構成を実現するため、ポータビリティ性や自律的運用が非常に重要になるので、今回はKubernetes上にShopSetを構築する道を選びました。

ShopSetアーキテクチャの要です。非常にたくさんの環境を構築することになるため、人間が管理するのは不可能です。そのため、そもそも人間による管理をしないことと、人間による管理をしないために規約を厳格に設計して、その規約のもと、自動化を徹底する方針を定めました。これが実装よりも大事な要です。

ShopSetがもつ規約

ShopSetがもつ規約を3つ定義しました。あとで紹介します。これらをKubernetes Custom Resourceとして、実装してシステムに強制させました。

まず1つ紹介します。Tierです。Tierは、レベリングされた更新単位のことを指します。ShopSetは必ず1つのTierに属して、リリースをTierにトリガーすると、そのTierに属したShopSetが更新される感じになります。

ここでいう“更新”はアプリケーションのアップデートや、マニフェストの更新などのすべてを指します。そして、同じTierに属するShopSetは、すべて同じタイミングで更新されることにします。

このTierがもつ、とある制約を定めます。すべての更新作業は、自身より低いレベルのTierより先に行われてはいけない制約を定めました。ちょっとわかりづらい。

つまりどういうことかというと、devやbetaなど、開発環境で使うようなTierを低レベルなものと設定し、prodなどを高レベルなTierに設定して、devから更新していきましょう、というような制約です。

こうすることで、下位のTierのリリースでデグレが発生した場合でも、それより上位のTierに影響が波及しないため、プロダクションなどを安全な環境で守れます。

もう1つ、ちょっと名前が大きいですが、Configuration。これは何かというと、開発環境やステージング環境、プロダクションなどを切り替えるためのアセットをひとまとめにモジュール化して、それぞれつけ替えて使いましょう、というようなものです。

Helmでいうvalues.yamlや、Kustomizeでいうpatchesなどを、抽象化した概念だと思ってもらえれば大丈夫です。

例えば、このようにステージングのConfigurationをShopSetに差し込むことで、同じバージョンのstg.prodを設定できます。今度は逆に、違うTierのShopSetに同じプロダクションのConfigurationを差し込むことで、バージョンの異なるprodを同時に稼働させたりする。このような用途を想定しています。

最後はFailure Domain、日本語に直訳すると“障害ドメイン”です。冗長構成を組んだときに、同時にダウンしないようにシステムで強制するものです。これは、ShopSetに所属するショップのスケジューリングに利用します。

先ほどの図の背景ですが、クラウドやKubernetesクラスタのレイヤーで障害が発生したとしても、冗長構成で動作を担保できるようにショップを配置する。そのために使うものです。

規約があることでよくなること

これらの制約があることで、何がよくなるのか紹介します。このような環境を仮想的に用意しました。クラウドをまたいだ複数クラスタで、透過的にShopSetがいくつか起動している状態です。

ShopSet上に、このようにShopSet間冗長が行えるようにショップを配置します。青と黄色と緑に関しては、2つのドメインで冗長、2つのクラスタ、2つのShopSetで冗長されていますが、赤と紫は冗長していないものをわざと用意しました。

この場合、クラスタが障害発生したときにどんなことが起こるか。Bが死んでしまって上のShopSetがぜんぜん動かなくなってしまった場合には、上に乗っている、青と黄色と緑と紫のショップは使えなくなります。ただ、青と黄色と緑は2ドメイン冗長されているため生き残ります。紫は残念ながらサービスが利用不可能になります。

死んでしまった場合、その死んでしまったShopSetから別のShopSetにショップを移動することによって、障害の復旧や冗長性の担保を回復させるオペレーションを行う想定です。

では、アプリケーションの更新はどのように行うのか。こちらは先ほどお話したとおり、Tier順に更新していきます。このようなTierに参加していると仮定します。dev、beta、beta-prod、prodという順番でTierのレベルが上がっていくことにします。

まずは低レベルなTier、devのTierで更新を実施したあと、動作確認を行います。この動作確認はポチポチでするもよし、実際にサービスにしてエラーレートの上昇をモニタリングするのもよいかと思います。

問題なければ次のレベルのTierの更新作業に移り、アラートが出なければどんどん高レベルのTierを動かしていきます。最後にprodのTierに更新が反映されて、めでたくすべてのShopSetが更新できた状態になります。

Kubernetesはクラスタのアップデートが非常に大変で有名ですが、そのクラスタアップデートについても言及しておきます。クラスタAをアップグレードするときは、まず上に乗っているShopSetから全部ショップを引っぺがして、ショップを別のところに移行させたいです。

そういうときに移行をバンっと叩いたら、Failure Domainをもとに別のShopSetに移行します。この場合、クラスタBはFailure Domainの条件を満たせないため、別のクラスタ、Bではないどこかに移ります。

クラスタAをアップグレードしてリバランスすることで、また使えるようになるようなオペレーションを考えています。

(次回につづく)