この記事は、BASE Advent Calendar 2022の18日目の記事(その2)です。
SRE Group の ngsw です。
先日ネットショップ作成サービス「BASE」は10周年を迎えました。
- 「BASE」サービスリリース10周年 ~「好きが、売れる。」をコアメッセージに特設Webサイトの公開とクーポンキャンペーンを開始~ | BASE, Inc.
- 10th Anniversaryクーポンキャンペーン は現在すでに終了しています
- 好きが、売れる。BASE・10周年特設サイト
せっかくの10周年です。ちなんだ記事を書けたら面白いかなとSRE関連のIssuesを振り返っていたのがこの記事のはじまりでした。
BASEの10年分のシステムの課題を読者の皆さんと共有できたならば面白いかな、というのが(後付けの)動機です。
SRE関連のIssuesはGitHub移行後の2016年より存在し、2022.12現在で4108個存在していました。2016年から7年弱分のIssuesからBASEの課題の移り変わりなど当時の状況を踏まえつつピックアップして紹介いたします。1
誤解を与えてしまうといけないので補足しますが、この記事内で「BASEでは」と記述されている場合、意味するのはサービス「BASE」のシステムまわりの話題であり、それを担当し責任をもつSREや開発陣の話題となっています。 組織であるBASEには、Data StrategyグループやBASE BANKセクションも存在し、それぞれが別のシステムを担当し管理しています。ある点においてサービス「BASE」のシステムよりもモダンな構成であったりしますので、事前に補足いたします。
AWS関連について
BASEは当初短い期間のオンプレミス時代以降、ずっとAWSで運用されてきました。いくつかのAWSアカウントが存在しますが、その中で最古のAWSアカウントの請求書日付をみてみると、2013年03月となっています。時間を追って費用をみていくと本格的に利用がはじまったのが2013年08月であろうと思われます。
VPC移行期(2016〜2017)
BASEはオンプレミスからAWSへの移行からしばらく、Classic環境で稼働していました。 そこからVPCへの移行計画がはじまります。
- VPCに本番RDS移行
- VPC移行ステップ
- VPC移行
- VPC移行第一ステップ
- VPC移行にあたりアプリケーションエンジニアにDBのホスト変更を依頼する
- VPC移行にあたりアプリケーションエンジニアにredisのホスト名を変更してもらう
- VPCにMySQLを移行する[スナップショット版]
- VPC移行 / 当日
ClassicとVPCとの違いは以下をご確認ください。
EC2-Classic - Amazon Elastic Compute Cloud
ここにある様々な制約の解決を目的とした移行計画となっており、おおよそ1年間をかけ対応が行われました。 切替作業当日は深夜メンテを行い、サービス停止のもと無事移行が完了しました。
リソース整理Issuesの登場(2017〜)
VPC移行という仕事を終え余裕ができたからかわかりませんが、AWSリソースを整理する目的のIssuesがたちはじめました。
- 開発アカウントのIAM整理
- AWS本番環境のACM整理
- 使用していないセキュリティグループの削除
- セキュリティグループ - 無制限アクセス
- IAM Access Key 不要なものは無効化/削除
開発速度を優先した結果、性善説に基づく牧歌的運用のつけをここから自覚しはじめる時期という、ある種あるあるな話題が、例にもれずBASEにも立ちはだかった瞬間でした。ここから2022年の今日においても、運用を続ける以上無視することができない一生ものの課題となっています。
2019年ごろには Trusted Adviser を、2021年には AWS Well-Architected を利用して、単純な整理だけでなくセキュリティ強度と開発速度の向上などの相乗効果なども視野に入れ活動をしています。後述しますがIaCなどはこの点を強く意識したものです。
うっかり対応期(2020〜)
この頃になると、後手にまわって対応が遅れてしまったな、というIssuesがいくつかみられるようになりました。
- [SES]v3署名非推奨のためv4署名への切替
- [VPN]AWS Client VPNの調査
- SubnetのIP枯渇問題の解消
v4署名切り替えに関しては、AWSからの周知メールにより発覚しました。 AWS Client VPNの調査が必要となったのは、2019年02月コロナ禍におけるリモートワーク全面切り替えのために対応する必要がありました。SubnetのIP枯渇問題は、コロナ禍における想定以上の急成長の対応で、増設を行ってきた結果黄色信号となったため対応した形でした。
ぎりぎりで回避できた点は不幸中の幸いですが、このような不必要な成功体験が積み重なっていくことは不幸中の不幸と言えるでしょう。
Linuxまわりについて
- ntpの設定
- CentOS7のcoreでカーネルパラメータを追加
- /proc/sys/net/ipv4/tcp_max_syn_backlogの値を変更
- カーネルパラメータチューニング
- chrony導入
- kernel_parameter
- EC2における単位時間あたりの名前解決制限対応
- EC2における単位時間あたりの名前解決制限の対応 - BASEプロダクトチームブログ で対応内容を解説しています
こちらについても前項で最後に先述したことと同じことが言えるでしょう。Issuesを追う限りは問題がでるまで設定が抜けていたんだな、という感想を持ちます。
この手の問題で難しいところは
- 決め打ちである程度まとめて事前に入れちゃう派
- 問題が起きてから入れる派
の二通りがあって、ngswはどちらかというと前者、BASEはどちらかというと後者であるという形です。 ただこれも結果論のところがあり、事前に設定しておくことで暗黙的に処理されることが果たして嬉しいのかどうか、という交換ではあると思います。
EC2デプロイまわりについて
BASEは少なくとも2016年ごろより、当時の担当者である @srockstyle によるIaCが進められていました。EC2まわりのほとんどがChefで記述、管理されており、2017年ごろには Provisioning や Deployment を chat-bot 経由で行えるよう整理されていきました。
作り込みが相当に入っており、自前のB/G DeploymentやRollback機能や、単純な増設機能を有しています。
- 自動デプロイメント改善案をつくる 2
- Mackerelを自動退役する
- デプロイした時のPRリストを取得&Slack通知する
- デプロイおよびアーキテクチャの改善プロジェクトを発足する
- プロビジョニングとデプロイの切り離し
ここでシステムの説明をしましょう。
- chat-bot(Hubot)
- api server(Rails)
- aws-sdk
- DB (MySQL)
chef-server(Chef)
Slackからchat-botへ投稿されたリクエスト文言を元に、api serverへさまざまな実行指示が飛びます。
- api server はAMIのもととなるEC2へデプロイ用のレシピを実行するchef-clientを投げ終了を待ちます。
- api server は終了を検知したのちaws-sdkを利用してAMI取得指示を出します。
- api server はaws-sdkを利用して3で作成したAMIをもとにB/Gデプロイメントを行います。
- api server は3〜4の間で、Insntace idやAMIの世代IDなど必要な情報をDBに書き込み管理のために利用します。AMIの世代IDがあるため、rollbackが可能となっています。
ほぼほぼの機能が2018年の段階で固まっており、2020年ごろより改修をいれ続け現在も現役で利用されています。その一方で様々な限界も見えつつあるのが現状であり、EC2からECSなどの乗り換えとあわせてデプロイ周りの見直しなどが必要なのではないか、というのが2022年現時点での課題であります。
ただ単純にEC2をECSにうつし、デプロイ周りを別機構にすればそれでOKという未来でもないよう考えており、開発陣からみた利便性と、システム全体のパフォーマンスとを比較勘案する必要があるでしょう。
当システムのB/Gデプロイメントの実現についてはここで解説されています。
IaCについて
chefの話題がでましたね。ついでなのでBASEにおける IaC 化対応について、どのような歴史があるのかご紹介したいと思います。
Chef期(2016〜)
- Chefのレシピ;Webサーバ関連:簡単な変更のみ
- Chefレシピ:Fluend導入周り
- Chefレシピ作成:deploy_branch(デプロイするレシピ)
- Chefのレシピ:基本部分
2016年のこの時点でChefまわりはほぼ固まっております。2022年現在でもChefは利用され、細かなリファクタリングなどを繰り返し整理運用されています。課題感については先述したデプロイまわりと重複するので割愛します。
AWS リソースまわりもIaC化したい(2019〜)
- [pj_lottery]SQSキュー、SNSトピック作成依頼
- 売上データダウンロードAppsに関してのAWSリソースの追加依頼
- [売上データダウンロードApps]S3 bucket追加と設定
- [売上データダウンロードApps]sqsの追加と設定
- [#base-apps-google_shopping_ads]SQSキュー、SNSトピック作成依頼
- [SNS, SQS作成依頼]顧客管理で使用するSNS, SQSのstg/prdでの設定
- [SNS, SQS作成依頼]リマインドSMS送信で使用するSNS, SQSのstg/prdでの設定
というような感じでS3やSQS、SNSなどのリソース作成依頼が、開発チームより続いたことがありました。2019年頃まではそもそも作業対応者によって構築方法がばらばらで、Web Consoleによる都度作成が行われていました。ここから作業手順の確立の意味をこめてaws-cliを利用したワンライナー構築が行われていきました。
賢明なる読者の皆さんはいま同じ感想をもっているはずです。 「他人の書いたaws-cli使い回すのやだなあ」 そうですね、そうなっていくのが自然です。自分の書いたaws-cliだって読み直すのは手間です。
ですので現在は
- EC2まわりはChefで
- AWSリソース周りはterraformで
という形にして後者を進めている形です。話題は変わりますが先述しているAWS Well-Architectedもこの判断に少なからず影響しています。
terraform 移行期(2021〜)
- Terraform Cloud / Team & Governance Plan の稟議を出す
- GHAでTerraformのplan/applyを実施できるようにする
既存リソースのimportとmoduleの作成を並行してすすめていく中で、2021年当初はterraform cloudをSREメンバーでのみ利用していました。しかしながら使い勝手の部分でGitHub Actionsのほうが勝るよう判断ができたので、2022年12月現在はGHAに寄せている状態です。社内のリポジトリにGHAのお手本がいくつか存在していたことなども、この判断の後押ししたのかもしれません。
terraform化に向けての具体的な行動は、この記事からはじまったと言ってもいいかもしれません。
Terraform導入への第一歩 - BASEプロダクトチームブログ
monitoring について
mackerel導入期(2017〜)
- mackerel監視項目追加
mackerel監視設定まわりの整理(2019〜)
- [mackerel]service,roleの整理
- [mackerel]監視項目の整理
- [mackerel]internal-api-batchのmackerel-agentインストールのリファクタ
- [mackerel]通知グループの整理
- [mackerel] アカウント周りの整理
- [mackerel][監視]Apache Server-StatusにてBusyWorkersの数値を閾値にして監視アラートあげたい
- [mackerel]監視対象候補の洗い出し
- [mackerel]service*roleを整理する
- [mackerel]監視項目の拡充(EC2)
- [Mackerel]サービス影響のあるクリティカルな取得リソース、監視項目の精査及び組み込み
- [Mackerel][nginx]プロセス監視
BASEにおいて監視周りはmackerelに強く依存している部分がありました。ある時期から特定時間帯に負荷高騰のアラートが鳴る状態が続いており、社内でみな敏感になっていました。最終的にはその敏感さが「いま重くない?」という会話を生むようになっていました。 携わるプロダクトのシステムに、メンバー全員が関心を持つことはとてもよいことですが、 「重いなあ/重くない?/そんなことないよ?」という個々の体感に基づいた、客観軸のない会話が多発することはよくないことと言えるでしょう。そのための対策が次項になります。
「ユーザからみてサービスが重い」とはどういうことか(2020〜)
- 「サービスが重い」の指標となる外形監視の見直し
- [BASE]Mackerel + Twilioによる特定アラート時の自動架電
外形監視を設定し、メトリクスをもつことでどのように重いのか、ユーザと近いかたちで常に同一の基準軸で「重い/重くない」の判断をつけられるようになりました。またあわせて「重い」と判断できるときにはプロダクトにとって重要な問題であると判断し、連携して架電発報するようしました。
気をつけないといけないのは、ここでのアラート対応は「重いという状態の定義ができ、それを越えたらアラートが出せるようになったね」というだけであって、「もっと速くできるんじゃないか?」ということに関しては無関心であるということです。たとえば常にレスポンスタイムが閾値98%のサービスは、アラート発報はしないが手放しで喜べるような状態ではありません。
New Relic(再)導入期(2020〜)
- [New Relic]chefの
.name
を appname に採用する - [NewRelic]Apacheを利用しないPHP稼働インスタンスに対して
- [NewRelic]internal-api-workerだけ暫定無効化する
- [New Relic][operation-controller]deploy marker用のAPIを設定する
- New Relic AWSインテグレーションでDSアカウントのメトリクスを取得できるようにする
先述した「もっと速くできるんじゃないか?」という課題感と、「それらのアクションをより開発陣主導で行うことができないだろうか」という組織的なストレッチ目標が New Relic (再)導入という意思決定を生みました。 Issues群は主にAPM初期導入設定時のいろいろな修正です。具体的な事例は本ブログの過去記事よりご覧いただけます。
- はじめてのNew Relic - 社内オンボーディングを開催いただきました - BASEプロダクトチームブログ
- New Relic User Group Vol.0で登壇しました #NRUG - BASEプロダクトチームブログ
- BASEの顧客管理はどのようにして実現されたか - BASEプロダクトチームブログ
- New Relic OneでDevOpsのキーメトリクス デプロイ頻度をグラフ化する - BASEプロダクトチームブログ
- NRUG (New Relic User Group) Vol.1に参加してきました - BASEプロダクトチームブログ
- レスポンス改善プロジェクトでやったこと - BASEプロダクトチームブログ
- 今BASEに入社してやることあるの?という疑問に答えるよ - BASEプロダクトチームブログ
- 商品在庫絞り込み機能のリリース振り返りと、New Relicを活用した観測について - BASEプロダクトチームブログ
DBまわりについて
Aurora移行(2017〜2018)
- 開発環境のRDSをAuroraにする
- 11月メンテ作業(Aurora移行)
クエリ効率化などは定期的に(2018〜)
- レプリカ向けるSQL
- SQLチューニング2019年2月
DBまわりについては2017年にRDS for MySQL時代からAurora v1(MySQL)へ移行しています。 またそれ以前からDBAを中心に細かい運用改善が繰り返し行われていました。 特にRDS時代にはストレージの残量について、意識を割かなければいけない状態だったことも強く関連していると思います。
コロナ禍の想定外の急成長(2020)
この時期の話題をCTOの川口さんに振ると、決まって「記憶がないんだよね」と返ってきます。「何を言ってんだ、こういうことがあったじゃないですか」と問いかけてみるけれど、そういうわたし自身も時系列がぐちゃぐちゃであったりします。つまり我々にはこのときの記憶があまりないです。これは冗談半分であり事実半分であるのが怖いところです。Issues振り返ってみても結局よくわからないんですよね。
そんなあやふやな中でも「Aurora DB Clusterへの新規接続時の問題、これが課題だよね」というのは、確実に共通している部分でありました。
RDS Proxy導入(2022)
- [#pj-rds-proxy]Subnet Group / Security Groupそれぞれ
- [#pj-rds-proxy]ph0, ph1
- [#pj-rds-proxy]RDS Proxy導入後のReader台数削減
「満を持して」という言葉がこれほど当てはまるシチュエーションは、人生を生きるなかでそうそうないでしょう。われわれは解決方法を手に入れたのです。さらに気持ちがよかったのはRDS Proxyを導入した後に、Readerの台数を削減できたことです。 個人的には「BASEシステム改善における2022年今年一番の大仕事」と考えています。メインを担当した @tadamatu には感謝しかありません。
Costについて
インフラコスト意識のたかまり(2018〜)
- 開発環境のAWSリソース整理と削除
- Data Transferの増加について
- RIの方針決め
- 商品画像で利用しているS3のドメイン分離
- Lambda makeThumbnail の廃止対応
- SavingPlan算出(2021/BASE)
- 2021年のRI/SavingPlan纏め
2018年当時に開発環境の整備の一環で、野放図になっていたAWSリソースの削除などが行われました。先述したリソース管理の意識の萌芽とはいったいなんだったのか。やはりこの手の問題は常に付きまとうものと思うほかありません。 主にこの手の意識を高くもってシステムを見守ってくれているのが浜谷さんです。
現在はSREチームを離れて他のチームに所属していますが、予算面についてはいまも担当してくれています。 過去にはこのような記事も書いています。
コスト削減の具体事例(2022)
- S3ストレージタイプ移行機能検証
- [S3]商品画像領域にlifecycleルール適用しINTELLIGENT_TIERINGにする
浜谷さんの過去の指摘内容であった、コスト削減案のひとつを今年完遂できたことは嬉しい話題です。 BASEではショップオーナー様が商品画像を登録する際に、本領域と解析のための別領域をS3 Bucket上に両方もっています。このうち削除可能な領域があり、この領域上のオブジェクト削除が課題となっていました。
当初は当該領域のオブジェクト削除においてaws-cliを用いることを想定して対応を進めていましたが、そもそものリスト出力ができないという状態で、しばらく手つかずの状態が続いていました。
ここで打開策として採用したのが、後付のlifecycleルールの設定で自動削除を待つというものです。削除領域が特定キー配下ということだけは確定していたので、一番手軽な方法であるという判断でした。これで相当なオブジェクト数を削除し、S3使用容量を大幅に削減できました。
しかしこのままでは結局時間稼ぎでしかないため、AWSの皆様や浜谷さんからのアドバイスを受け、INTELLIGENT_TIERINGの導入を行った次第です。 話は変わりますがわたしは前職、前々職で動画配信サービスのインフラを担当しており「頻繁にアクセスされる動画が存在し、その反面まったくアクセスされない動画がそれ以上に存在する」ということを肌感覚で知っていました。「おそらくBASEのような大小さまざまなショップへのリクエストも似たような形であろう」という点からINTELLIGENT_TIERINGの可能性を感じました。
その上で性能面で懸念があったため、INTELLIGENT_TIERINGそのもの検証とレスポンス速度の確認を行い、さらにAWSサポートより「性能差はない」「ただしオブジェクト監視の費用がかかる」という回答もいただいたことで導入を行った形です。
独自ドメインApp と Nginx について
独自ドメインApp HTTPS化対応期(2016〜2018)
- Certbotを試す
- 独自ドメインSSL基盤サーバのChef
- 独自ドメインSSL: ngx_mruby対応
- 独自ドメインSSLサーバのcore
- 独自ドメインSSL:の取得サーバのnginx
- 独自ドメインSSL:デプロイレシピ
- 独自ドメインSSL:rsyncサーバの実装
- 独自ドメインSSLサーバのchefレシピ
- 独自ドメインSSL CentOS7対応 / Core
- 独自ドメインSSL CentOS 7対応 / Rubyインストール
- 独自ドメインSSL CentOS7対応 / reverse-proxy対応
- 独自ドメインSSLのCentOS7化にむけて、coreの編集。
- 独自ドメインSSL CentOS7対応 / デプロイ
- global reverse proxyと独自ドメインSSLのwwwユーザのIDは同じでなければならないことをChefに記述する
- certbotのインストールをyumで
- yumでcertbotコマンドをインストールするようにした
- 独自ドメインSSL残課題
- 独自ドメインApps の証明書切れを事前に検知できるようにする
Let's Encryptの活用により、オーナー様が持ち込んだ独自ドメイン名に対して、証明書を発行できるようになりました。もちろん証明書の発行だけでなくWebサーバで証明書を認識できなくてはなりません。その手のシステムを開発したのが先ほども登場した @srockstyle です。
詳しくは本ブログ内の以下エントリがわかりやすいかもしれません。
対応当時のリリースはこちらです。
この機能がもしなかったと仮定した場合、「ショップ開設を行おう」「このまま引き続きBASEを使っていこう」というショップごとそれぞれの意思決定が、どれだけの数YesからNoになっていたことでしょうか。ショップにとって独自ドメイン名の持ち込みは、サービスにロックインしないための最後の砦とも言えるので、その手段を安全に提供できていることをわれわれはもっと誇っていいのかもしれません。 さらにはその誇りを実現してくれているのはLet's Encryptの存在であるという気持ちを、忘れてはいけません。スポンサーになろう。
Let's Encrypt 対応期(2019〜2020)
- [domainssl] Let'sEncrypt 2020.02.29 CAA Rechecking Bug
- [domainssl]2020.09末期限 / Let's Encrypt延命のために必要なこと
Let's Encrypt 周りに関して、運用不要というわけではありません。小さな悩みごと、対応しなければならないことにいくつかぶち当たる場面がありました。
- CAA Rechecking Bug
- 認証局のルート証明書の切り替え問題
- 外部のブログ記事でいうと songmu さんのブログエントリがわかりやすいです
このあたりは既に懐かしく思えますね。
CertbotからLegoへ(2021)
- [EOL][domainssl]certbot-autoが1.11.0で非推奨になる
- [domainssl]certbot->lego置き換えのリリース計画
先述した個別の対応とは別に、Certbotまわりのバージョン管理などで億劫に思えることが多くなりました。具体的にはCertbotとPythonのバージョンとの話題です。BASEではCentOSを利用している背景があり、Pythonのバージョンを云々するのがちょっとめんどうな点があります。
上記にいつまで悩まされるか、ということを損失と捉え、ここでLegoに乗り換えることにしました。 ここで誤算がありました。「Certbotはかなり親切にディレクトリを切ってくれるつくりだったんだな」というところです。このLet's Encryptを利用した独自ドメインAppのシステムは、Certbotのディレクトリ構成に強く依存しているつくりになっていました。
ですのでLego導入時にCertbotのディレクトリ構成を再現させる補助となるShell Scriptをあわせて配置して、Railsに実行させるようにするなどの工夫が必要となりました。
Nginxのアップデート(2020〜2022)
- IP個別に単位時間あたりのリクエスト数を制限する
- 1.15.x -> 1.19.x
http_limit_req_module
導入時にlimit_req_dry_run
を利用したかったため
- nginx 1.19.6 -> 1.21.5 にアップデートするまでの道のり
- nginx-buildとngx_mrubyの対応のため
証明書が配置され、ショップの正面玄関として重要な存在となったNginxですが、現行のバージョンと乖離した状態になっていました。またそもそもの動機として limit_req_dry_run
を採用したいためアップデートが必要となってきました。nginx-buildとngx_mruby、またpcre、OpenSSL、zlib、ngx_dynamic_upstreamとそれぞれのバージョンで整合性を持たないといけないため、buildを行っているchefレシピの修正を行いました。この修正で1.19.xおよびOpenSSLのバージョンを最新のものにアップデートすることができ、目的となる http_limit_req_module
および limit_req_dry_run
の導入に成功しました。
また1.19.6利用時にpcre問題が発生しました。こちらの catatsuy さんのエントリが問題発生当時の状況を把握する参考になります。
最終的にはわれわれはpcre2を採用する、つまりNginxのアップデートをし、CHANGES を睨んで確認事項を洗い出し必要なディレクティブやパラメータの変更を行うよう対応しました。
また副次的な恩恵として、OpenSSLアップデート対応をカジュアルに行えるようになったことがあげられるでしょう。
結びに
10年間のうち7年弱のIssuesを振り返ってみました。ここに書ききれなかった日々の小さな対応や、ログ基盤や新カートまわりの話題などもあったわけですが、SREの活動を振り返るには充分であろうと自負があります。
ここには見栄も背伸びもありませんので、読者のみなさんの「このあたりの施策が足りないんじゃないか」「俺だったらこうやってもっとうまくやったな」などの感想は妥当かもしれません。ですのでもしよかったらBASEで一緒に実現していただけると嬉しい気持ちです :-) <ホントダヨ
明日19日は @glassmonekey、 @take61___0 のお二人のエントリです。 BASEアドベントカレンダー2022を引き続きお楽しみいただければ幸いです。