GMO Developers Night で発表した内容です
1カラーミーショップの可用性向上のためのインフラ刷新高橋 拓也 @ GMO ペパボ2021/04/13GMO Developers Night
View Slide
22アジェンダ● 自己紹介● カラーミショップが抱える課題● 可用性向上への道○ 分離環境の誕生● ShopSet アーキテクチャ○ 概念○ 実装○ 導入と課題● まとめ
3自己紹介3
44高橋 拓也 (takutaka)自己紹介● インフラエンジニア @ GMO ペパボ● 所属: 技術部 技術基盤チーム● 自宅サーバを飼っています● https://github.com/takutakahashi● https://www.takutakahashi.dev● https://twitter.com/takutaka1220写真
55高橋 拓也 (takutaka)自己紹介● 所属: 技術部 技術基盤チーム○ 事業部のお手伝いをしたり、○ 全社的なインフラ基盤を開発したりするチーム● 自宅サーバを飼っています● https://github.com/takutakahashi● https://www.takutakahashi.dev● https://twitter.com/takutaka1220写真WS 兼 k8s nodek8s nodek8s master Backup HDDルーター (VyOS)おもちゃ箱10G Switch
66カラーミーショップ
77
8解決したい課題8
99EC の需要が増加🏠
1010大量に売り上げるショップが増えた🚀
1111システムへの負荷がすごいことに🔥
1212システムへの負荷解決したい課題- 需要増加に伴う負荷の集中- 人気商品に対する大量アクセス- bot を使った DDoS に近いアクセスも...
1313システムへの負荷解決したい課題- カラーミーはマルチテナント型アーキテクチャ- すべてのショップアクセスが同じサーバを通る- 人気ショップの負荷が他のショップに波及
1414システムへの負荷解決したい課題- カラーミーはマルチテナント型アーキテクチャ- すべてのショップアクセスが同じサーバを通る- 人気ショップの負荷が他のショップに波及サービス全体がダウンしてしまう障害が発生してしまった😢
1515流通増加による可用性への重要度の増加解決したい課題- カラーミーを利用した流通額の増加- 数分のダウンが無視できない規模感へと成長- ショップオーナーから可用性への期待値が上がる
1616流通増加による可用性への重要度の増加解決したい課題- カラーミーを利用した流通額の増加- 数分のダウンが無視できない規模感へと成長- ショップオーナーから可用性への期待値が上がるシステムの安定性を更に向上させる施策が必要になった
17可用性向上への道17
1818最初の施策: 分離環境可用性向上への道- とあるショップの負荷でサービスダウンが発生カラーミー
1919最初の施策: 分離環境可用性向上への道- 既存のシステムのクローン(分離環境)を構築カラーミーカラーミー分離環境
2020最初の施策: 分離環境可用性向上への道- 対象ショップのみ向き先を変更カラーミーカラーミー分離環境
2121最初の施策: 分離環境可用性向上への道- 非常に効果的にワークした- 特定のショップの負荷による全体のダウンをある程度防げるようになった
2222最初の施策: 分離環境可用性向上への道- 非常に効果的にワークした- 特定のショップの負荷による全体のダウンをある程度防げるようになった分離環境を応用して多くの課題を解決できるのでは?🤔
2323分離環境の応用カラーミーカラーミー分離環境カラーミーカラーミーカラーミーカラーミーカラーミーカラーミーカラーミーN 環境ゼロコストで分離環境を作成し高トラフィック対策以外でも利用する
24ShopSet アーキテクチャ分離環境改め24規約を盛り込んだ分離環境
2525ShopSetAPIショップページカートプロキシ LBhttps://hoge.shop-pro.jpShopSet … ユーザーが決済完了までで通るコンポーネントをまとめたもの複数のショップの集合体だから ShopSethttps://foo.shop-pro.jp
2626ShopSetAPIショップページカートプロキシ LBhttps://hoge.shop-pro.jpShopSetAPIショップページカートプロキシ LBひとつ以上の ShopSet で冗長構成を取る
27AWSOn-Prem27ShopSetAPIショップページカートプロキシ LBhttps://hoge.shop-pro.jpShopSetAPIショップページカートプロキシ LBShopSet のポータビリティを高めマルチクラウド構成を取ることでプラットフォーム冗長を実現する
28AWSOn-Prem28ShopSetAPIショップページカートプロキシ LBhttps://hoge.shop-pro.jpShopSetAPIショップページカートプロキシ LBShopSet のポータビリティを高めマルチクラウド構成を取ることでプラットフォーム冗長を実現する自律的構築運用とポータビリティを実現するためにKubernetes 上に ShopSet を構築する
2929ShopSet アーキテクチャの要ShopSet アーキテクチャ- 大量の環境を管理することは非常に大変- 以下の指針を設定- 人間による管理をしない- 規約を厳格に設計し、規約のもと自動化を徹底する
3030ShopSet が持つ規約ShopSet アーキテクチャ新たな概念を導入する- Tier- Configuration- Failure Domain
3131ShopSet が持つ規約ShopSet アーキテクチャ新たな概念を導入する- Tier- Configuration- Failure DomainKubernetes Custom Resource として実装し規約をシステムに強制する
32- レベリングされた更新単位のこと- ShopSet は必ずひとつの Tier に所属する- 同じ Tier に属する ShopSet はすべて同タイミングで更新される32TierShopSet アーキテクチャTier 1shopset shopsetTier 2shopset shopsetTier 3shopset shopsetリリースはTier 単位でトリガ
33- すべての更新作業は自身より低い Tier より先に行われてはいけない33Tier が持つ制約ShopSet アーキテクチャ
34- すべての更新作業は自身より低い Tier より先に行われてはいけないdev34TierShopSet アーキテクチャbetaprod-betaprodprod-hadev → beta → prod-beta …の順で更新する
35- すべての更新作業は自身より低い Tier より先に行われてはいけないdev35TierShopSet アーキテクチャbetaprod-betaprodprod-ha下位 Tier のリリースでデグレードした場合でも上位 Tier に影響が波及しない
36- すべての更新アセットは低い Tier で動作検証済みのものを使う36TierShopSet アーキテクチャbetaprodbeta betaprodbeta値をコピーせず同じものを参照manifests, image, etc...
37- 接続する環境を切り替えるためのもの- Dev, Staging, Production など- Helm でいう values.yaml, Kustomize でいう patches37ConfigurationShopSet アーキテクチャ
3838ConfigurationShopSet アーキテクチャTier 1shopset 2shopset 1productionstaging同じバージョンのstg, prod を設定
3939ConfigurationShopSet アーキテクチャTier 1shopset 2shopset 1productionバージョンの異なるprod を同時に稼働Tier 2
40- 障害ドメイン- ShopSet に所属するショップのスケジューリングに利用- 複数 ShopSet を利用した冗長構成を組む40Failure DomainShopSet アーキテクチャ
41AWSOn-Prem41ShopSetAPIショップページカートプロキシ LBhttps://hoge.shop-pro.jpShopSetAPIショップページカートプロキシ LB クラウドやクラスタのレイヤで障害が発生しても冗長構成で動作を担保できるようにショップのスケジューリングをする
4242制約があることでよくなること
4343k8s Cluster A(On-Prem)k8s Cluster B(EKS)ShopSetA-1A-2 B-1 B-2 C-1 C-2k8s Cluster C(On-Prem)クラウドを跨いだ複数クラスタで透過的に同一環境が動作する
4444k8s Cluster A k8s Cluster BProdA-1ProdA-2ProdB-1ProdB-2k8s Cluster A(On-Prem)k8s Cluster B(EKS)2ドメイン冗長冗長なしk8s Cluster BProdC-1ProdC-2k8s Cluster C(On-Prem)ShopSet 間冗長を行うようにショップを配置するShopSetA-1A-2 B-1 B-2 C-1 C-2
4545クラスタ障害発生時
4646k8s Cluster A k8s Cluster BProdA-1ProdA-2ProdB-1ProdB-2k8s Cluster A(On-Prem)k8s Cluster B(EKS)2ドメイン冗長冗長なしk8s Cluster BProdC-1ProdC-2k8s Cluster C(On-Prem)とあるクラスタが動作不能になるShopSetA-1A-2 B-1 B-2 C-1 C-2
4747k8s Cluster A k8s Cluster BProdA-1ProdA-2ProdB-1ProdB-2k8s Cluster A(On-Prem)k8s Cluster B(EKS)2ドメイン冗長冗長なしk8s Cluster BProdC-1ProdC-2k8s Cluster C(On-Prem)このユーザーがサービス利用不可能になるShopSetA-1A-2 B-1 B-2 C-1 C-2
4848k8s Cluster A k8s Cluster BProdA-1ProdA-2ProdB-1ProdB-2k8s Cluster A(On-Prem)k8s Cluster B(EKS)2ドメイン冗長冗長なしk8s Cluster BProdC-1ProdC-2k8s Cluster C(On-Prem)これらのユーザーのアクセスは守られるShopSetA-1A-2 B-1 B-2 C-1 C-2
4949k8s Cluster A k8s Cluster BProdA-1ProdA-2ProdB-1ProdB-2k8s Cluster A(On-Prem)k8s Cluster B(EKS)2ドメイン冗長冗長なしk8s Cluster BProdC-1ProdC-2k8s Cluster C(On-Prem)ShopSetA-1A-2 B-1 B-2 C-1 C-2利用する ShopSet を変更して復旧
5050アプリケーション更新
5151k8s Cluster A k8s Cluster BA-1 A-2 B-1 B-2k8s Cluster A(On-Prem)k8s Cluster B(EKS)2ドメイン冗長冗長なしk8s Cluster BC-1 C-2k8s Cluster C(On-Prem)Tier 順に更新する
5252k8s Cluster A k8s Cluster BA-1beta-prodA-2prodB-1prodB-2beta-prodk8s Cluster A(On-Prem)k8s Cluster B(EKS)2ドメイン冗長冗長なしk8s Cluster BC-1betaC-2devk8s Cluster C(On-Prem)更新順:1. dev2. beta3. beta-prod4. prod
5353k8s Cluster A k8s Cluster BProdA-1ProdA-2ProdB-1ProdB-2k8s Cluster A(On-Prem)k8s Cluster B(EKS)2ドメイン冗長冗長なしk8s Cluster BProdC-1ProdC-2k8s Cluster C(On-Prem)更新順決定:1. C-22. C-13. A-2, B-14. A-1, B-2ProdA-1beta-prodProdA-2prodProdB-1prodProdB-2beta-prodProdC-1betaProdC-2dev更新順:1. dev2. beta3. beta-prod4. prodA-1beta-prodA-2prodB-1prodB-2beta-prodC-1betaC-2dev低レベルの Tier で更新実施後動作確認を行う
5454k8s Cluster A k8s Cluster BProdA-1ProdA-2ProdB-1ProdB-2k8s Cluster A(On-Prem)k8s Cluster B(EKS)2ドメイン冗長冗長なしk8s Cluster BProdC-1ProdC-2k8s Cluster C(On-Prem)更新順決定:1. C-22. C-13. A-2, B-14. A-1, B-2ProdA-1beta-prodProdA-2prodProdB-1prodProdB-2beta-prodProdC-1betaProdC-2dev更新順:1. dev2. beta3. beta-prod4. prodA-1beta-prodA-2prodB-1prodB-2beta-prodC-1betaC-2dev問題なければ次のレベルの Tier を更新する
5555k8s Cluster A k8s Cluster BProdA-1ProdA-2ProdB-1ProdB-2k8s Cluster A(On-Prem)k8s Cluster B(EKS)2ドメイン冗長冗長なしk8s Cluster BProdC-1ProdC-2k8s Cluster C(On-Prem)更新順決定:1. C-22. C-13. A-2, B-14. A-1, B-2ProdA-1beta-prodProdA-2prodProdB-1prodProdB-2beta-prodProdC-1betaProdC-2dev更新順:1. dev2. beta3. beta-prod4. prodA-1beta-prodA-2prodB-1prodB-2beta-prodC-1betaC-2devアラートがでなければ次へ
5656k8s Cluster A k8s Cluster BProdA-1ProdA-2ProdB-1ProdB-2k8s Cluster A(On-Prem)k8s Cluster B(EKS)2ドメイン冗長冗長なしk8s Cluster BProdC-1ProdC-2k8s Cluster C(On-Prem)更新順決定:1. C-22. C-13. A-2, B-14. A-1, B-2ProdA-1beta-prodProdA-2prodProdB-1prodProdB-2beta-prodProdC-1betaProdC-2dev更新順:1. dev2. beta3. beta-prod4. prodA-1beta-prodA-2prodB-1prodB-2beta-prodC-1betaC-2dev更新完了
5757クラスタアップグレード
5858k8s Cluster A k8s Cluster BProdA-1ProdA-2ProdB-1ProdB-2k8s Cluster A(On-Prem)k8s Cluster B(EKS)k8s Cluster BProdC-1ProdC-2k8s Cluster C(On-Prem)Cluster A をアップグレードするProdA-1beta-prodProdA-2prodProdB-1prodProdB-2beta-prodProdC-1betaProdC-2devA-1beta-prodA-2prodB-1prodB-2beta-prodC-1betaC-2dev
5959k8s Cluster A k8s Cluster BProdA-1ProdA-2ProdB-1ProdB-2k8s Cluster A(On-Prem)k8s Cluster B(EKS)k8s Cluster BProdC-1ProdC-2k8s Cluster C(On-Prem)同一 Tier の ShopSet へショップを割り振るProdA-1beta-prodProdA-2prodProdB-1prodProdB-2beta-prodProdC-1betaProdC-2devB じゃないどこかCluster B はFailure Domain の条件を満たせないため別のクラスタに移るA-1beta-prodA-2prodB-1prodB-2beta-prodC-1betaC-2dev
6060k8s Cluster A k8s Cluster BProdA-1ProdA-2ProdB-1ProdB-2k8s Cluster A(On-Prem)k8s Cluster B(EKS)k8s Cluster BProdC-1ProdC-2k8s Cluster C(On-Prem)クラスタをアップグレードするProdA-1beta-prodProdA-2prodProdB-1prodProdB-2beta-prodProdC-1betaProdC-2devB じゃないどこかA-1beta-prodA-2prodB-1prodB-2beta-prodC-1betaC-2dev
6161k8s Cluster A k8s Cluster BProdA-1ProdA-2ProdB-1ProdB-2k8s Cluster A(On-Prem)k8s Cluster B(EKS)k8s Cluster BProdC-1ProdC-2k8s Cluster C(On-Prem)ProdA-1beta-prodProdA-2prodProdB-1prodProdB-2beta-prodProdC-1betaProdC-2devB じゃないどこかA-1beta-prodA-2prodB-1prodB-2beta-prodC-1betaC-2dev別のクラスタからショップを再配置する
6262ShopSet の実装
6363実装への課題ShopSet の実装- 制約をどのように実装するか?- オペレーションがソフトウェアにロックインされるのでは?
6464制約をどのように実装するか?ShopSet の実装- Custom Resource と Controller を実装する- 自律的に動作させられる- 人間からわかりやすい単位に抽象化できる- フレームワークに乗れば実装も楽
6565オペレーションがソフトウェアにロックインされるのでは?ShopSet の実装- 単体のシステムから抜けられないのはつらい- Kubernetes- Custom Controller- Custom Controller しかオペレーションできないと...- Controller を頻繁に更新できない- Controller の障害時に対策が何もできない- つらい
6666Controller からロジックを分離する
6767Controller からロジックを分離するShopSet の実装- Controller でしかできないオペレーションをなくす- 人間が(多少大変でも)容易に再現可能とする
6868Controller からロジックを分離するShopSet の実装- Controller でしかできないオペレーションをなくす- 人間が(多少大変でも)容易に再現可能とするGitOps をベースにmanifests の生成を自動化する
6969GitOps?ShopSet の実装- Git Repository を唯一の成果物とするデプロイ方式- リポジトリのマニフェストを Kubernetes Cluster に同期する- ArgoCD が有名
7070GitOps?ShopSet の実装- ArgoCD は `git pull` して `kubectl apply -f ` するだけ- ArgoCD が apply できる = 人間が apply できる- ArgoCD を中間レイヤにすれば複雑性を吸収できる
7171GitOps?ShopSet の実装- ArgoCD は `git pull` して `kubectl apply -f ` するだけ- ArgoCD が apply できる = 人間が apply できる- ArgoCD を中間レイヤにすれば複雑性を吸収できるArgoCD が apply できるリポジトリをController で自動生成する
7272ShopSet の実装Kubernetes ClusterGitHub(Enterprise)shopset-controllerKubernetes APIapply -f tier.yamlapply -f shopset.yamlpush assetsfetchapplyfetchshopsetdeployAPICartProxy
7373shopset-controller がやることShopSet の実装- Kustomization で使う差分ファイルの生成とプッシュ- base manifests の更新- ArgoCD Application リソースの作成と apply
7474shopset-controller が操作するリポジトリShopSet の実装- system-repository- overlays に相当するファイルを保存- shopset-controller が生成したファイルをプッシュ- ArgoCD が参照して Cluster に Apply する- app-repository- base に相当するファイルを保存- 人間が作成しプッシュ- system-repository から git submodule として参照される
7575リポジトリを tier.yaml に記述するShopSet の実装
7676Kustomization で使う差分ファイルの生成とプッシュShopSet の実装
7777Git Submodule で最新の base を参照し続けるShopSet の実装
7878ArgoCD の Custom Resource を生成ShopSet の実装
7979shopset-controller + GitOps で制約を実装ShopSet の実装- Tier の実装- tier ごとに branch を生やす- 最下位 tier で変更を実装する- tier branch の変更を上位 branch に push
8080ShopSet の実装 リポジトリの関係性開発者shopset-system (branch:tier-0)overlays/shopset1baseshopset-system (branch:tier-1)overlays/shopset2baseshopset-apps (branch:tier-0)api cart proxyshopset-system (branch:tier-4)overlays/shopset3baseshopset-apps (branch:tier-1)api cart proxyshopset-apps (branch:tier-4)api cart proxyPR/Mergesubmoduleargocd
8181ShopSet の実装 リポジトリの関係性開発者shopset-system (branch:tier-0)overlays/shopset1baseshopset-system (branch:tier-1)overlays/shopset2baseshopset-apps (branch:tier-0)api cart proxyshopset-system (branch:tier-4)overlays/shopset3baseshopset-apps (branch:tier-1)shopset-apps (branch:tier-1)shopset-apps (branch:tier-4)api cart proxyshopset-apps (branch:tier-4)api cart proxyPR/MergesubmoduleargocdブランチでTier を分ける
8282ShopSet の実装 リポジトリの関係性開発者shopset-system (branch:tier-0)overlays/shopset1baseshopset-system (branch:tier-1)overlays/shopset2baseshopset-apps (branch:tier-0)api cart proxyshopset-system (branch:tier-4)overlays/shopset3baseshopset-apps (branch:tier-1)api cart proxyshopset-apps (branch:tier-4)api cart proxysubmoduleargocdPR/Merge一番下のTier branch にPR を出す
8383ShopSet の実装 リポジトリの関係性開発者shopset-system (branch:tier-0)overlays/shopset1baseshopset-system (branch:tier-1)overlays/shopset2baseshopset-apps (branch:tier-0)api cart proxyshopset-system (branch:tier-4)overlays/shopset3baseshopset-apps (branch:tier-1)api cart proxyshopset-apps (branch:tier-4)api cart proxysubmoduleargocdPR/Merge自動デプロイされるので動作確認する
8484ShopSet の実装 リポジトリの関係性開発者shopset-system (branch:tier-0)overlays/shopset1baseshopset-system (branch:tier-1)overlays/shopset2baseshopset-apps (branch:tier-0)api cart proxyshopset-system (branch:tier-4)overlays/shopset3baseshopset-apps (branch:tier-1)api cart proxyshopset-apps (branch:tier-4)api cart proxysubmoduleargocdPR/Merge動作確認できたら次の tier branch に変更を反映する
8585shopset-controller + GitOps で制約を実装ShopSet の実装- Configuration の実装- git repository + Tier branch で管理
8686shopset-controller + GitOps で制約を実装ShopSet の実装- ShopSet は tier と configuration を指定するだけ
8787shopset-controller + GitOps で制約を実装ShopSet の実装- Failure Domain の実装- これから
8888現状と課題
8989ShopSet の開発体制現状と課題- プロジェクトとしてチーム開発中- @takutaka1220 … shopset の設計、実装, etc- @MITLicense … App の k8s-convert, ログ転送基盤の構築, etc- @ch11aki … Middleware の k8s-convert, クラスタ設計, etc- @takapi86 … App の k8s-convert, セキュリティ, etc
9090ShopSet の開発体制でうまくいったこと現状と課題- 一時間ほど集合するわいわいタイムを毎日開催- 作業やってもいいし、雑談してもいいし、来なくてもいい- MTG や同期的に作業をやる場合はこの時間をあてがう
9191ShopSet の開発体制でうまくいかなかったこと現状と課題- 一時間ほど集合するわいわいタイムを毎日開催- 作業やってもいいし、雑談してもいいし、来なくてもいい- MTG や同期的に作業をやる場合はこの時間をあてがう
9292ShopSet のマイルストーン現状と課題- 検証環境にて長期安定稼働中- 約半年くらいトラブルなし- 制約の設計は概ねうまくいった
9393ShopSet のマイルストーン現状と課題- ShopSet で構築した環境をプロダクションに一部導入済み- 本日の午前中にリリースしました🎉- 単一クラスタ、単一 ShopSet 構成
9494ShopSet 開発の課題現状と課題- k8s-convert がとても大変- ドメイン知識豊富な専門家で 1 month/app くらいかかる- 構成の共通化や cluster-wide の機能提供で対応- ログ収集 (fluentd) や、監視とアラート(prometheus) など
9595ShopSet 開発の課題現状と課題- プロダクト開発体制の構築- k8s に慣れた人だけがプロダクト開発するわけじゃない- デバッグやリリースを補助するインターフェースが必要- `shopctl` コマンドを現在設計中
9696ShopSet 開発の課題現状と課題- ShopSet で動作させるカラーミー環境の最適化- キャパシティの把握- どのくらいリクエストを食えるのかわからない- 1クラスタ上でどのくらい ShopSet をスケールさせるべきか?
9797ShopSet 開発の課題現状と課題- ShopSet で動作させるカラーミー環境の最適化- Microservice のベストプラクティスの吸収- rate limit & circuit breaker とか- observability とか
9898ShopSet 開発の課題現状と課題- ShopSet で動作させるカラーミー環境の最適化- 次のボトルネックへの対処- 無限に ShopSet を作るには?- おそらく DB Connection が枯渇しそう
9999ShopSet 開発の課題現状と課題- プロダクト運用の簡素化- ショップの追加、 ShopSet の変更など- どの ShopSet を使えばいいの?などの迷いを無くす- 規約を用いて自動化する方針
100100ShopSet 開発の今後現状と課題- ShopSet に内包する Service の拡充- k8s-convert との戦い- AWS EKS を用いたマルチクラウドの本番適用- ほぼできるはず- マルチ k8s クラスタのハンドリングの実装- クラスタライフサイクル管理、Failure Domain 実装、etc...
101101アジェンダ● 可用性向上への道○ 分離環境の誕生● ShopSet アーキテクチャ○ 概念■ Tier■ Configuration■ Failure Domain○ 実装■ GitOps + ArgoCD○ 導入と課題
102102おしまい