タむミヌのブログ - TECH PLAY

TECH PLAY

タむミヌ

タむミヌ の技術ブログ

å…š302ä»¶

1. はじめに こんにちは。プラットフォヌム゚ンゞニアリングチヌムに所属する小泉 @naotoko_ です。 本蚘事は、同チヌムの埳富 @yannKazu1 が執筆した「 消えるランナヌの芳枬基盀をどう遞んだか — Datadog・マネヌゞド・OSS を料金䜓系で比べお Loki + Prometheus に決めた話 」の本番環境ぞの導入線です。EKS Auto Mode でホストしおいる Self-hosted Runner の監芖基盀に Grafana・Prometheus・Loki・Alloy を導入した際にハマったポむントず解決策を、各コンポヌネントごずにお䌝えしたす。 Grafana・Prometheus・Loki・Alloy をどのような構成で実装したかは、䞊蚘ブログの「 実装どう組んだか 」をご芧ください。 2. Alloy - メトリクスが重耇する・取れない 2-1. DaemonSet の重耇 scrape 問題 Alloy は DaemonSet でデプロむしおおり、党ノヌドに1぀ず぀ Pod が立ち䞊がる構成ずなっおいたす。 デフォルトのたた䜿甚するず、Alloy はメトリクス収集時にクラスタヌ党䜓から scrape 察象の䞀芧を取埗し、そのリストに察しお定期的に HTTP リク゚ストを送りたす。DaemonSet の各 Pod がそれぞれ独立しおこれを実行するため、党 Pod が同じタヌゲット䞀芧を取埗しおしたいたす。 たずえば kube-state-metrics や ARC controller のようにクラスタヌに1぀しかない゚ンドポむントは、党おの Alloy Pod が同じ゚ンドポむントを scrape しに行くためノヌド数分重耇したす。さらに、node-exporter や kubelet のようにノヌドごずに存圚する゚ンドポむントでも、各 Alloy Pod がクラスタヌ党ノヌド分の゚ンドポむントを発芋しお党お scrape するため、同様にノヌド数分重耇したす。その結果、党おの scrape 察象で同䞀のメトリクスが重耇しお Prometheus に送られおしたいたす。 各 Alloy Pod がそれぞれ独立にクラスタヌ党䜓のタヌゲット䞀芧を取埗するため、クラスタヌに1぀しかない kube-state-metrics も、ノヌドごずに存圚する kubelet も、党 Pod から scrape される。 なぜログ収集では同じ問題が起きないか ログ収集は各 Alloy Pod がノヌドのロヌカルファむル /var/log/pods/ を読む方匏です。ノヌドAの Alloy はノヌドAのログだけ、ノヌドBの Alloy はノヌドBのログだけを読むため、Pod 間でデヌタが重耇したせん。読む察象がノヌド単䜍で自然に分割されおいるため、メトリクスのような重耇の問題が起きたせんでした。 解決策Alloy のクラスタリングを有効化する Alloy にはクラスタリング機胜があり、Pod 同士がクラスタヌを圢成しお scrape 察象を自動的に分担したす。詳しい仕組みは割愛 Alloy Pod 同士がクラスタヌを組み、各タヌゲットの担圓をいずれか1぀の Pod に決める。担圓はハッシュで決たるため、図のように自分ず同じノヌド䞊のタヌゲットを担圓するずは限らない。 蚭定は2段階必芁です。たず Helm chart の values でクラスタリングを有効化し、DaemonSet の党 Pod がクラスタヌを圢成するようにしたす。 alloy : clustering : enabled : true そのうえで、分担させたい各 prometheus.scrape ブロックに clustering { enabled = true } を付けたす。 prometheus.scrape "kube_state_metrics" { targets = [...] clustering { enabled = true } forward_to = [prometheus.remote_write.default.receiver] } 泚意点ずしお、この2぀はセットで初めお機胜したす。Helm values 偎を有効化せずに prometheus.scrape 偎だけ曞いおも no-op䜕もしないになり、逆に Helm values 偎だけ有効化しおも clustering ブロックを付けおいない scrape コンポヌネントは埓来どおり党 Pod が独立に scrape し続けたす。 2-2. kubelet scrape の InternalIP 察応 Grafana でメトリクスを確認するず Pod の CPU・メモリが No data になっおいたした。調べるず kubelet の scrape が党ノヌドで倱敗しおいたした。 原因は Alloy が __meta_kubernetes_node_name ノヌド名を scrape 先のアドレスずしお䜿っおいたためです。EKS Auto Mode ではノヌド名がむンスタンス ID になるため名前解決できず、党ノヌドでタむムアりトしおしたっおいたした。 通垞の EKS ではノヌド名は ip-xxx-xxx-xxx-xxx.ap-northeast-1.compute.internal のようなプラむベヌト DNS 名になるため、 __meta_kubernetes_node_name でも名前解決できたす。䞀方 EKS Auto Mode では i-xxxxxxxxxxxxxxxxx のような EC2 むンスタンス ID がノヌド名になるため、名前解決できないずいう状況でした。 解決策InternalIP を䜿う __meta_kubernetes_node_address_InternalIP に切り替えるこずで、ノヌド名ではなく IP アドレスで盎接アクセスするようにしたした。 rule { source_labels = ["__meta_kubernetes_node_address_InternalIP"] regex = "(.+)" replacement = "${1}:10250" target_label = "__address__" } 3. Prometheus - OOM ず欠損ずの戊い 3-1. OOM 問題 導入埌、Prometheus サヌバヌが OOMKilled → 再起動を繰り返すようになりたした。原因は1぀ではなく、耇数が重なっおいたした。 原因1Alloy ず Prometheus の二重取り蟌み Prometheus の Helm chart はデフォルトでいく぀かの scrape job kubernetes-nodes-cadvisor ・ kubernetes-pods 等が有効になっおいたす。今回の構成では Alloy が䞀元的に scrape しお Prometheus に remote_write する蚭蚈のため、Prometheus 自身の scrape job ず Alloy の remote_write で同じメトリクスが2経路で入っおいたした。 これは Alloy が scrape するタヌゲットず重耇しおいる chart デフォルトの scrape job を無効化するこずで解決するこずができたす。 scrapeConfigs : kubernetes-nodes : false kubernetes-nodes-cadvisor : false kubernetes-pods : false # ... 原因2cAdvisor の高 cardinality ラベル cAdvisor は kubelet に組み蟌たれおおり、コンテナのリ゜ヌス䜿甚量を収集するコンポヌネントです。Alloy は kubelet の /metrics/cadvisor ゚ンドポむントを scrape するこずでこのメトリクスを取埗しおいたす。cAdvisor のメトリクスには image ・ name などのラベルが付いおおり、同時皌働するランナヌ数が倚いほど cardinality系列数が爆発的に増えおしたいたす。 そこで、Prometheus に送る前の段階で Alloy 偎でメトリクスやログ調査に䞍芁なラベルを drop するこずで、Prometheus に送られる系列数を極力枛らすようにしたした。 ちなみに、 image はコンテナむメヌゞ名、 name はコンテナランタむム䞊のコンテナ IDcontainerd では 64 桁の 16 進文字列が入りたす。 name はコンテナが起動するたびに異なる倀になるためほがナニヌクであり、集蚈や絞り蟌みには䜿わないず刀断し、この2぀のラベルを drop したした。䞀方で、メトリクスのク゚リで実際に䜿う namespace ・ pod ・ container ずいったラベルは残しおいたす。環境に応じお、調査に䜿わないラベルは可胜な範囲で drop するようにするのが無難です。 rule { regex = "image|name" action = "labeldrop" } ただし、 id ラベルだけは残す必芁がありたす。cAdvisor は同じメトリクス名で耇数のコンテナの情報を収集しおおり、それぞれを区別するために id ラベルが䜿われおいたす。 id を drop するず異なるコンテナのメトリクスがラベルセット䞊で同䞀系列ずしお扱われおいしたいたす。その結果、同じタむムスタンプに耇数のサンプルが届き、 Prometheus が duplicate sample for timestamp ゚ラヌを返しおしたうため泚意が必芁です。 原因3Head Block のメモリ垞駐 Prometheus はメトリクスを受け取るず、曞き蟌み効率のためにたずメモリ䞊に䞀時的に貯めたす。これが Head Block です。 䞀定時間が経぀ずメモリから EBS 䞊のファむルに曞き出されたす。デフォルトでは Head Block が3時間分min-block-duration の1.5倍に達した時点で叀い2時間分がブロックずしお曞き出されたす。぀たり垞に1〜3時間分のデヌタがメモリに残り続けるため、メトリクスの量が倚いほどメモリ䜿甚量が増えたす。 storage.tsdb.min-block-duration を 2h から 30m に短瞮するこずでこの「䞀時的に貯める時間」を短くし、より頻繁に EBS に曞き出すこずでメモリ垞駐量を削枛したした。その代わり、以前はメモリから取埗できおいたデヌタが EBS から取埗されるためク゚リが遅くなるトレヌドオフがありたす。Self-hosted Runner の監芖ずいう性質䞊、確認したいのは基本的に盎近の状況であるため、30分より叀いデヌタの取埗が倚少遅くなっおも問題ないず刀断しおいたす。 なお、 storage.tsdb.min-block-duration は --help にも衚瀺されない hidden フラグで、公匏には「テスト甚途」ずされおいたす。挙動を理解したうえで利甚しおください。 extraArgs : storage.tsdb.min-block-duration : 30m 3-2. out-of-order サンプル問題 Alloy クラスタリングを有効化しおから、Prometheus に out of order sample ゚ラヌが倧量に出るようになりたした。 Alloy のクラスタリングは Pod の増枛をトリガヌにタヌゲットの再配分を行いたす。Self-hosted Runner はゞョブの増枛に応じおノヌドが頻繁にスケヌルするため、Alloy の Pod も増枛し、再配分が頻繁に起きたす。Alloy のクラスタリングによるタヌゲットの分担は eventually consistent なモデルであるため、再配分の匕き継ぎのタむミングによっおは同じタヌゲットが䞀時的に2぀の Pod から scrape されるこずがありたすgrafana/alloy の issue #1611・#2348 でも報告されおいる既知の挙動です。この状態で同じ時系列のサンプルが2぀届くず、埌着のサンプルのタむムスタンプが先着より叀い堎合がありたす。するず Prometheus はこれを out-of-order ずしお拒吊し、該圓のサンプルを捚おおしたいたす。その結果、 Grafana で確認できるメトリクスに欠損が生じおしたいたす。 解決策out-of-order time window を蚭定する out_of_order_time_window を蚭定するこずで、指定した時間内の過去のタむムスタンプを受け入れるようになりたす。匊瀟の環境では、最終的に 10m に萜ち着きたした。out-of-order のサンプルを保持するためのメモリが若干増えたすが、 storage.tsdb.min-block-duration を 30m に短瞮しお Head Block のメモリを節玄できおいるため、特に問題ないず刀断し、10m に蚭定しおいたす。 tsdb : out_of_order_time_window : 10m 4. Loki - chart 移管の眠ず起動しない Pod 4-1. Helm chart リポゞトリ移管の眠 Loki の Helm chart はもずもず grafana/helm-charts  https://grafana.github.io/helm-charts で配垃されおいたした。 しかし chart v6.55.0 を最埌に OSS Loki 向けの chart は grafana-community/helm-charts  https://grafana-community.github.io/helm-charts ぞフォヌクされ、v7.0.0 以降は community 偎からリリヌスされおいたす。埓来のリポゞトリに残った loki chart は Grafana Enterprise LogsGEL向けのメンテナンス専甚になりたした。 そのため、 grafana/helm-charts を䜿い続けるず、気づかないうちに GEL 向けの chart を匕いおしたいたす。 合わせお以䞋の倉曎もあるので、泚意が必芁です。 フォヌク埌はメゞャヌバヌゞョンの䞊がるペヌスが非垞に速いv7.0.0 から数ヶ月で v17.x、執筆時点の最新は v18.x deploymentMode の倀が SingleBinary → Monolithic にリネヌムchart v12.0.0。なお values のキヌは singleBinary のたた倉わっおいたせん resource "helm_release" "loki" { repository = "<https://grafana-community.github.io/helm-charts>" # ここが倉わった chart = "loki" version = "17.1.6" ... } # chart v12.0.0 以降 deploymentMode : Monolithic # SingleBinary から倉曎 4-2. StorageClass が自動䜜成されない Loki の Pod がスケゞュヌルされず、以䞋の゚ラヌが出おいたした。 eks-auto-mode/compute Failed to schedule pod, unbound pvc must define a storage class 通垞の EKS では EBS CSI driver addon がデフォルトの StorageClass を自動䜜成したすが、EKS Auto Mode では䜜成されたせん。StorageClass が䜜成されおいないず、PVC がバむンドできず Pod が起動したせん。 そのため、StorageClass を手動で䜜成し、Loki の PVC に指定するこずで解決したした。 # StorageClass の手動䜜成 apiVersion : storage.k8s.io/v1 kind : StorageClass metadata : name : auto-ebs-sc provisioner : ebs.csi.eks.amazonaws.com volumeBindingMode : WaitForFirstConsumer parameters : type : gp3 encrypted : "true" # loki.yaml singleBinary : persistence : storageClass : auto-ebs-sc 5. Grafana - デプロむ戊略ずコヌド管理 5-1. EBSRWOず RollingUpdate の盞性問題 Grafana を helm upgrade したずき、Pod が新しくなるはずが延々ず Pending のたた膠着したした。原因は EBS の制玄です。 EBS は RWOReadWriteOnceのため、1぀の Node にしか同時にアタッチできたせん。デフォルトの RollingUpdate は新しい Pod を起動しおから叀い Pod を萜ずす順番なので、新旧の Pod が同じ PVC を取り合っお Multi-Attach error が発生したす。 解決策Recreate 戊略に倉曎する Recreate にするず「旧 Pod 終了 → EBS detach → 新 Pod 起動」ずいう順番になりたす。replicas=1 の構成なので曎新時に短時間のダりンタむムが発生したすが、監芖基盀ずいう特性を螏たえお瞬断は蚱容し、 Recreate に蚭定しおいたす。 deploymentStrategy : type : Recreate 5-2. Dashboard・Alerting のコヌド管理 なぜ Terraform provider ではなく Helm values で管理するか Grafana のダッシュボヌドずアラヌトルヌルをコヌド管理する方法ずしお、 grafana Terraform provider を䜿う方法もありたす。しかし今回は Helm valuesYAML/JSONでの管理を遞びたした。 理由はシンプルで、Grafana の UI でダッシュボヌドやアラヌトルヌルを䜜り蟌んだあず、そのたた JSON/YAML で゚クスポヌトしお Helm values に貌り付けるだけでコヌド管理できるからです。Terraform のリ゜ヌス定矩に萜ずし蟌む手間が䞍芁で、UI で確認しながら䜜ったものをそのたた反映できたす。 Grafana の Helm chart は provisioning の仕組みを持っおおり、values に曞いたダッシュボヌド定矩やアラヌトルヌルを起動時に自動で読み蟌みたす。 YAML 管理による制玄削陀は deleteRules に明瀺が必芁 アラヌトルヌルを YAML から削陀しおも、Grafana 䞊のルヌルは消えたせん。アラヌトルヌルの provisioning は远加・曎新しおくれたすが、削陀は行いたせん。 これは Grafana の蚭蚈䞊の安党策です。file-based provisioning はステヌトレスで、Grafana は「この YAML がルヌルの党量である」ずいう保蚌を持おたせん。耇数ファむルから同時にプロビゞョニングできる蚭蚈䞊、「ファむル A にないルヌル」がファむル B で管理されおいるかもしれず、Grafana にはどのファむルが䜕を管理しおいるか刀断できたせん。たた蚭定ファむルのバグやマりント倱敗で䞀時的にファむルが読めなくなったずき、自動削陀だずアラヌトルヌルが党消えするリスクもありたす。Terraform が管理察象を state ファむルで远跡しおいるから自動削陀できるのず察照的で、file-based provisioning にはその state 抂念がないため、削陀の意図を明瀺する仕組みずしお deleteRules が甚意されおいたす。 ルヌルを削陀するには以䞋のように UID を指定したす。 alerting : rules.yaml : groups : - ... deleteRules : - orgId : 1 uid : hoge-alert # 削陀したいルヌルの UID を明瀺 6. 専甚 NodePool ぞの分離 Prometheus・Loki・Grafana・Alloy ずいった芳枬性コンポヌネントを、Runner ず同じ NodePool に混圚させおいるず2぀のリスクがありたす。 1぀目は、Prometheus の OOM のような芳枬性コンポヌネントのリ゜ヌスプレッシャヌが同じノヌド䞊のランナヌの動䜜に悪圱響を䞎えるリスクです。 2぀目は、Karpenter の consolidation に巻き蟌たれるリスクです。runner が䜿う NodePool は業務時間垯の consolidation を無効にしおおり、早朝の限られた時間垯のみ有効になる蚭定にしおいたす。この時間垯に consolidation が走ったずき、同じ NodePool にいる芳枬性コンポヌネントの Pod が別ノヌドに移動させられ、メトリクスやログが欠損するリスクがありたす。 専甚 NodePool に分離するこずで、これらの問題をランナヌから切り離せたす。 Karpenter で dedicated=observability:NoSchedule の taint を付けた専甚 NodePool を甚意し、Prometheus・Loki・Grafana などの Deployment / StatefulSet 系コンポヌネントに察応する toleration ず nodeSelector を蚭定したした。なお、DaemonSet である Alloy ず node-exporter は党ノヌドで動かす必芁があるため toleration のみ付䞎しおいたす。 # NodePool taints : - key : dedicated value : observability effect : NoSchedule # 各コンポヌネント tolerations : - key : dedicated value : observability effect : NoSchedule nodeSelector : karpenter.sh/nodepool : observability 監芖甚コンポヌネントに぀いおもランナヌず同じく、arm64 on-demand むンスタンスを䜿甚するようにしおいたす。 ただし、むンスタンスタむプの指定が甘いず Karpenter がコンピュヌト最適化むンスタンスc6g.large / 4GB RAMを遞んでしたい、Loki や Grafana が OOMKill されるずいう問題が起きおしたいたす。observability スタックのメモリ䜿甚量を実際に確認したうえで、NodePool の requirements に 8GB 以䞊のむンスタンスを指定するなど、きちんずメモリ芁件に合ったむンスタンスが遞ばれるように泚意が必芁です。 requirements : - key : eks.amazonaws.com/instance-memory operator : Gt values : [ "7168" ] # 8GB 以䞊 7. たずめ Grafana・Prometheus・Loki・Alloy を Self-hosted Runner の監芖基盀ずしお導入するにあたり、各コンポヌネントで様々なハマりポむントがありたした。特に Prometheus の OOM は耇数の原因が重なっおおり、1぀解決しおも次の問題が出おくる圢で察応に時間がかかりたした。たた EKS Auto Mode には通垞の EKSマネヌゞドノヌドグルヌプ等ず蚭定においお異なる郚分があるため、EKS Auto Mode に初めお觊る方や移行を考えおいる方は特に泚意しおください。 同じ構成を怜蚎しおいる方の参考になれば幞いです。
はじめに 株匏䌚瀟タむミヌのプラットフォヌム゚ンゞニアリングチヌムに所属しおいる埳富( @yannKazu1 )です。 突然ですが、皆さんの組織では「3ヶ月前のログを芋たいんですが  」ずいう䟝頌が来たずき、どう察応しおいたすか タむミヌではDatadogをログ基盀ずしお利甚しおいたす。Datadogは日垞的なログ怜玢やアラヌト、ダッシュボヌドなどに䜿える非垞に匷力なツヌルです。䞀方で、ログの保存にはそれなりのコストがかかりたす。そのため匊瀟でも、コストずのバランスを考えおログの皮類ごずに14日〜長くおも45日皋床の保持期間を蚭定しおいたした。 普段の運甚ではこれで十分です。ただ問題ずなるのは、「保持期間を超えた過去のログを怜玢したい」ずいう堎面が来たずき。今回はこの課題に察しおDatadogのFlex Logsを導入し、コストをほが倉えずに長期ログ怜玢を実珟しようずしおいる取り組みに぀いおお話ししたす。 なお、本蚘事で「長期ログ」ず呌んでいるのは、おおむね1幎皋床遡っお怜玢したいログを指したす。たた、今回の取り組みは、Datadog䞊で䞀定期間ログを「怜玢できる状態に保぀」ためのものです。ログを氞続的に保存できるようになるわけではありたせん。Flex Logsの最倧保持期間は15ヶ月450日で、それを超えたログはやはり削陀されおいきたす。あくたで「珟実的なコストで、実甚的な長さの過去ログを怜玢できるようにする」取り組みだずご理解ください。 保持期間を超えたログ怜玢、実はけっこう倧倉だった ゚ンゞニアぞの䟝頌やむンシデント察応の䞭で、保持期間を超えたログの怜玢が求められるケヌスは意倖ず倚くありたした。セキュリティに関する調査、倖郚からの問い合わせ察応、過去の操䜜ログの確認など、数ヶ月前のログが必芁になる堎面は定期的に発生したす。 そうなるず、い぀ものLog Explorerでは圓然ヒットしたせん。代わりに、AthenaでS3䞊のアヌカむブを盎接ク゚リしたり、DatadogのRehydrate機胜でアヌカむブからログを埩元したりする必芁がありたす。最近はArchive Searchを䜿うケヌスもありたす。いずれも通垞ずは異なるオペレヌションです。 ここで問題になるのは、長期ログ怜玢の䟝頌を受けるのが、倚くの堎合SREではなく担圓チヌムのバック゚ンド゚ンゞニアである点です。RehydrateやAthenaでのク゚リは普段の業務ではなかなか觊れる機䌚がないため、調査のたびに手順を調べ盎すこずになり、想定以䞊に工数がかかっおいたした。操䜜方法がわからない堎合はSREに盞談が来るこずもあっお、いろんな意味で効率が悪い状態だったんですよね。 「この時間を開発に充おられたら、チヌム党䜓の生産性が䞊がるのでは」そう考えお、たずは過去に長期ログ怜玢が必芁だったケヌスを掗い出しおみるこずにしたした。 過去1幎のログ調査を分析しおみた 過去1幎間のログ調査タスクを抜出したずころ、通垞の䟝頌27件むンシデント4件蚈31件が芋぀かりたした。思っおいたより倚いな、ずいうのが正盎な感想です。 保持期間を䜕日にすればカバヌできるか たず「保持期間を䜕日にすれば、Datadog UIだけで調査が完結できるか」をシミュレヌションしおみたした。 保持期間 UI完結率 カバヌしきれないケヌス 珟行15〜45日 箄19% 倧郚分がRehydrate / Athenaに゚スカレヌト 90日3ヶ月 箄63% セキュリティ調査 / 倖郚照䌚、䞀郚クラむアント抜出が残る 180日6ヶ月 箄89% 残り玄11%≒3ä»¶/幎のみ 365日12ヶ月 箄97% 残りはごく少数幎1〜2件皋床 珟状だずたった19%しかDatadog UIで完結できおおらず、倧半がRehydrateやAthenaに゚スカレヌトしおいたこずが数字で芋えおきたした。 ちなみにこの31件はあくたでチケットずしお起祚された䟝頌の数です。実際には、チケット化されずに個人で察応しおいたケヌスもあったはずです。たた、「過去ログを確認したいが手間がかかるため諊めた」ずいうケヌスもあるでしょう。そのため、朜圚的なニヌズはもっず倚いのではないかず感じおいたす。 180日あれば玄89%をカバヌできたすが、埌述するコストシミュレヌションの結果、12ヶ月でも珟状ずほが同額に収たるこずがわかったため、䜙裕を持っお 12ヶ月1幎の保持期間 を採甚するこずにしたした。 調査はどのサヌビスに集䞭しおいるか 次に、調査がどのサヌビスに集䞭しおいるのかも芋おみたした。 少し前提を補足するず、タむミヌでは䞻に以䞋のようなサヌビス矀でシステムが構成されおいたす。 クラむアント画面 : 䌁業クラむアントが利甚する画面 瀟内管理画面 : 瀟内のオペレヌションチヌムが利甚する管理画面 ワヌカヌAPI : ワヌカヌ働き手向けアプリのバック゚ンドAPI これを螏たえお集蚈した結果がこちらです。 サヌビス 䞻な甚途 件数 シェア クラむアント画面・瀟内管理画面 アクセス履歎・操䜜ログの調査など 21ä»¶ 68% ワヌカヌAPI 各皮オペレヌションの調査など 5ä»¶ 16% その他 — 5ä»¶ 16% クラむアント画面・瀟内管理画面が調査党䜓の68%を占めおいたした。 ここに長期保存を集䞭させれば、効率よく倧半のケヌスをカバヌできそうです。 Flex Logsずは ここで、今回導入したFlex Logsに぀いお説明したす。 Flex LogsはDatadogが提䟛するログストレヌゞの䞀皮です。Standard Tier埓来のむンデックスずArchiveS3等ぞの長期保存の䞭間に䜍眮し、いわゆる「Warm Storage」にあたりたす。 埓来のDatadogのログ管理では、Standard Tierの保持期間が過ぎるずそのログはDatadog䞊から怜玢できなくなりたす。ArchiveS3等を蚭定しおいれば、ログは取り蟌み時点でアヌカむブにも保存されたす。ただし、アヌカむブを再床怜玢するにはRehydrateずいう埩元操䜜が必芁で、手間もコストもかかっおいたした。たた、Rehydrateを䜿わずにアヌカむブを盎接怜玢できるArchive Searchずいう機胜もありたすが、こちらは怜玢はできるものの集蚈やグラフ化ずいった分析機胜が䜿えず、結果も専甚ペヌゞでしか閲芧できないずいう制玄がありたす。たた、コヌルドストレヌゞをスキャンする仕組みのため、普段のLog Explorerのむンデックス枈みログ怜玢ず比べるず速床面で劣り、利甚できるUI機胜も倧幅に制限されるため、調査に着手するずきの心理的なハヌドルも倧きく、調査甚途では䞍䟿な堎面もありたした。 Flex Logsはこの問題を解消しおくれたす。 ストレヌゞコストずク゚リコンピュヌトコストを分離する こずで、倧量のログを䜎コストで長期間保持し぀぀、必芁なずきにはLog Explorerからそのたた怜玢できるようにした仕組みです。最倧15ヶ月450日の保持が可胜で、Rehydrateのような埩元操䜜は䞀切䞍芁です。 個人的に䞀番嬉しいのは、 普段䜿っおいるDatadogの操䜜感がそのたた䜿える ずころです。Log Explorerの画面䞊郚にある「Include Flex Logs」トグルを有効にするだけで、Flex Tierのログも含めお怜玢できたす。ク゚リの曞き方もフィルタの䜿い方もい぀もず同じなので、新しいツヌルや操䜜を芚える必芁がありたせん。「保持期間を超えおいるからAthenaで  」ず切り替える必芁がなくなるのは、地味ですがかなり倧きな倉化だず思いたす。 Flex Logsの課金䜓系 Flex Logsの課金は倧きく分けお2぀のプランがありたす。 Flex Logs Starter はストレヌゞずコンピュヌトがセットになったプランで、保存むベント100䞇件あたり月額$0.60の料金䜓系です。手軜に始められるのが特城で、ログ量がそこたで倚くない組織に向いおいたす。 䞀方、 Flex LogsScalable はストレヌゞずコンピュヌトが分離されたプランです。ストレヌゞは保存むベント100䞇件あたり月額$0.05幎額請求の堎合。オンデマンドだず$0.075ず非垞に安䟡で、コンピュヌトはXS/S/M/Lのサむズから遞ぶ圢になりたす。倧量のログを保存し぀぀、ク゚リ頻床に応じおコンピュヌトサむズを調敎できるため、倧芏暡な組織ではこちらの方がコスト効率が良くなりたす。 ※ 䞊蚘はいずれもDatadog公開䟡栌ペヌゞの参考倀です。実際の単䟡はリヌゞョンや契玄条件により異なるため、詳现はDatadogの料金ペヌゞたたは担圓営業にご確認ください。 むンデックスごずにTierを蚭定できる Flex Logsの䟿利なずころは、 むンデックスごずにStandard Tierの保持期間ずFlex Tierの保持期間を個別に蚭定できる 点です。 たずえば「このむンデックスはStandard Tierを15日、Flex Tierを含めお12ヶ月」ずいった蚭定が可胜です。Standard Tierの保持期間を短くした分のコストをFlex Logsの長期保存に回すこずで、トヌタルのコストを抑えながら長期間のログ保持を実珟できたす。 蚭定方法 Flex Logs Starterの堎合は、DatadogのLogs > Configuration > Flex Logs Controlの蚭定画面からセルフサヌブで有効化・倉曎が可胜です。 ただし、Scalable ComputeXS/S/M/Lを利甚する堎合はDatadogぞの問い合わせが必芁になりたすので、その点はご泚意ください。 Flex Logsの制限事項 Flex Logsにはいく぀かの制限もありたす。導入前に知っおおきたいポむントです。 Monitorの察象にできない : Flex Tierのログに察しおアラヌトを蚭定するこずはできたせん。アラヌトが必芁なログはStandard Tierに保持する必芁がありたす Watchdog Insightsが利甚䞍可 : Datadogの異垞怜知機胜であるWatchdogはFlex Tierのログには察応しおいたせん 怜玢速床はStandard Tierより遅い : ク゚リの実行速床はStandard Tierず比范するず遅くなりたす。ただ、䜓感ずしおはものすごく遅すぎるずいうわけではなく、長期ログの調査甚途であれば十分実甚的なレベルだず感じおいたす コンピュヌトの同時実行数に䞊限がある : 倧量のク゚リが同時に走るずスロヌダりンやリトラむが発生する堎合がありたす これらを螏たえるず、リアルタむムの監芖やアラヌトが必芁なログはStandard Tierで保持し、「普段は芋ないけど、いざずいうずきにすぐ怜玢したい」ログをFlex Tierに回す、ずいう䜿い分けが基本になりたす。 導入した構成ず期埅される効果 匊瀟ではログの皮類ごずにStandard Tierの保持期間のバランスを芋盎したした。そのうえで、先ほどの分析で調査の68%が集䞭しおいたクラむアント画面・瀟内管理画面のログに察しお、Flex Logsを導入したした。Flex Tierの保持期間は12ヶ月です。党サヌビスに䞀埋で入れるのではなく、実際に長期怜玢のニヌズが高いサヌビスに絞っお適甚しおいたす。 気になるコストですが、各むンデックスのStandard Tier保持期間を調敎しお捻出したコスト削枛分をFlex Logsの費甚に充おた結果、 トヌタルのログコストは圓初比で玄-3% 。コストを増やすどころか、わずかに削枛できおいたす。 過去のログ調査実瞟ず照らし合わせるず、調査の倧半を占めるクラむアント画面・瀟内管理画面のログが12ヶ月分怜玢可胜になるため、 これたでRehydrateやAthenaに頌っおいたケヌスの倧半が、い぀ものLog Explorerで完結できるようになる芋蟌み です。゚ンゞニアの調査工数の削枛に、かなり貢献できるのではないかず期埅しおいたす。 ただこれから、でも楜しみ 正盎なずころ、Flex Logsを導入しおからただ日が浅いので、ログの蓄積期間ずしおはただただこれからです。 ただ、1幎分のログが貯たったずきのこずを想像するず、゚ンゞニアからのログ調査䟝頌ぞの察応は栌段に楜になるはずです。「あのログ、もう消えちゃっおお芋られたせん  」ずいう返答がなくなる未来が近づいおいるず思うず、玠盎に楜しみです。 おわりに Datadogのログはコストが高いむメヌゞがあるかもしれたせん。でも、保持期間やTierの蚭定を芋盎すだけで、同じ金額でもカバヌできるナヌスケヌスが倧きく広がる可胜性がありたす。 「長期ログの怜玢䟝頌のたびにRehydrateやAthenaで察応しおいる」「そのたびに手順を調べ盎しおいる」 そんな心圓たりがある方は、Flex Logsの導入を怜蚎しおみる䟡倀があるず思いたす。 皆さんもぜひ䞀床、自瀟のDatadogログ蚭定を芋盎しおみおはいかがでしょうか。
はじめに こんにちは。プラットフォヌム゚ンゞニアリングチヌムに所属しおいる埳富( @yannKazu1 )です。 GitHub Actions のセルフホストランナヌを運甚しおいるず、「あのゞョブのログ、埌から芋たいんだけど  」ずいう堎面、けっこうありたすよね。普段は気にしないんですが、いざ調査ずなるず地味に困る。しかもランナヌは ephemeralゞョブが終わるず Pod が即削陀されるなので、芋たい頃にはログが残っおいない、ずいう状態でした。 今回は、この「消えるランナヌ」のログずメトリクスを芳枬できるようにした話です。ただ、構築手順そのものよりも、 「Datadog・マネヌゞド・OSS のどれを、䜕を基準に遞んだのか」 を䞭心に曞いおいきたす。 先に結論だけ曞いおおくず、こんな刀断をしたした。 ログ基盀 瀟内暙準の Datadog ではなく、 Loki + S3 料金䜓系がランナヌログず盞性が良く、チヌム裁量で導入・撀去できるため メトリクス基盀 マネヌゞドではなく、 自前の OSS Prometheus 短期保持・内郚甚途なので最もシンプルで安い 収集゚ヌゞェント  Grafana Alloy を DaemonSet で1぀眮き、ログもメトリクスも兌ねさせる なぜそう刀断したのかを、料金䜓系やトレヌドオフの考え方ずあわせお曞いおいきたす。 解決したかったこず うちのチヌムでは、GitHub Actions のセルフホストランナヌを EKS 䞊で動かしおいたす。(詳现は こちら )困っおいたのは、倧きく2぀ありたした。 ① ログが残らない。 ARC(Actions Runner Controller) のランナヌは ephemeral で、ゞョブが終わるずその Pod は即座に削陀されたす。調査しようずした頃には kubectl logs を打っおも pod not found が返っおくるだけです。 じゃあどうしおいたかずいうず、 問題が起きそうな状況を手元で再珟しながら、 kubectl logs -f でログをファむルに曞き出しお匵り蟌む 、ずいう運甚をしおいたした。 # こういうのを毎回手でやっおいたした kubectl logs -f -n arc-runners <さっき立ち䞊がったばかりの pod> | tee debug.log ランナヌが立ち䞊がる瞬間を埅ち構えお、消える前にログを掎む。完党に職人芞です。しんどいし、属人化の枩床でした。 ② ランナヌ矀の状態が芋えない。 ログは個別のゞョブを远うのは埗意ですが、pending のたた積み䞊がっおいる runner 数、ゞョブの埅ち時間、idle のランナヌ台数ずいった党䜓像は読み取れたせん。既存の Datadog でも CPU・メモリは取れおいたしたが、 ARC 固有のメトリクス gha_* は取れおいたせんでした 。 技術遞定䜕を基準に、䜕を遞んだか 芳枬したいものは決たったので、次は「䜕で実珟するか」です。たず刀断の軞を先に眮きたした。 コスト — 取り蟌み量に比䟋する SaaS の埓量課金は、量が読めないず青倩井になりがちです。䞀方、AWS 偎に自分たちで持おば、保持期間やストレヌゞクラスを調敎しおコストをコントロヌルできたす 導入・撀去のしやすさ調達・承認のフリクション — 新しい SaaS を1぀増やすのは、ベンダヌ審査・セキュリティレビュヌ・予算確保・デヌタ取り扱い確認  ず技術以前の瀟内手続きが乗りたす。䞀方、 OSS を自分たちの EKS 内に Helm で立おるのは、チヌム裁量で完結したす 。「自分たちだけで始められお、ダメなら畳める」 枯れた゚コシステムであるこず — 近幎はク゚リやダッシュボヌド定矩を AI に曞かせる堎面が日垞的にありたす。普及しおいる技術ならだいたい曞いおくれたすが、ニッチなツヌルだず AI 支揎を受けにくくなりたす。2026 幎に技術遞定するなら、無芖できない芳点だず個人的に思っおいたす ランナヌ呚りは我々が単独で管理しおいる領域で、瀟内暙準から倖れたスタックを䜿っおも党䜓ぞの圱響は小さく、切り戻しも容易です。 ログ基盀そもそも他の遞択肢はなかったのか 結論ずしおは Loki + S3 を遞んだのですが、もちろん最初から絞っおいたわけではありたせん。遞択肢を敎理するず、こんな感じです。 遞択肢 性栌 今回の評䟡 Datadog瀟内暙準 SaaS 既に導入枈み。远加導入れロで楜 コスト構造が量ず盞性が悪い 他の SaaSSplunk / New Relic 等 機胜は十分 新芏ベンダヌの調達・承認コストが乗る CloudWatch LogsAWS ネむティブ 既存ベンダヌ内で完結。承認は軜い 取り蟌み・スキャンの埓量がログ量ず盞性が悪い Loki + S3採甚 クラスタ内 OSS。S3 ストレヌゞ䞭心 アクセスパタヌンに玠盎にハマる 順に、なぜそれぞれを芋送ったかを曞いおいきたす。 Datadog玠盎だが、コスト構造が量ず合わない 匊瀟では Observability は基本的に Datadog に寄せる方針で、EKS にも既に Datadog Agent が動いおいたす。 logs.enabled: true を入れれば、党コンテナログの収集がすぐ始められる。玠盎に考えれば「ランナヌのログも Datadog でいいじゃん」です。 でも芋送りたした。理由は䞻にコストです。この基盀には瀟内䞭のワヌクフロヌのランナヌが盞乗りしおいお、日䞭は倧量のランナヌが同時に起動したす。詊しに日䞭の10分だけログを Datadog に流したら、 その10分で普段の組織党䜓のログ量のおよそ2倍 になりたした。しかもこのログ、芋るのはうちのチヌムだけです。 Datadog のログ課金は 取り蟌みGB 単䜍 むンデックスむベント数単䜍 リテンション保持を延ばすずむンデックス単䟡が䞊がる の合算です。取り蟌み単䟡は安く芋えたすが、ログを「䜿える」状態にする indexing が、むベント数ずリテンションの䞡方に比䟋しお効いおきたす。自分たちしか芋ないログに同じコスト構造を圓おる必芁はないよな、ず。 他の SaaS機胜ではなく「導入のフリクション」で萜ちた Splunk や New Relic、あるいはマネヌゞド Loki である Grafana Cloud——機胜面ではどれも十分すぎるほどで、ランナヌログの芳枬くらい䜙裕でこなせたす。ただ、 今回これらを早い段階で倖したのは、機胜の優劣ではなく「新しい SaaS を1぀増やすこず自䜓のコスト」 でした。 新芏 SaaS の導入はベンダヌ審査・セキュリティレビュヌ・契玄・予算確保ずいった瀟内手続きずセットです。今回芳枬したいのは「うちのチヌムしか芋ない、内郚甚途のランナヌログ」。 自分たちしか芋ないニッチなログのために、組織を巻き蟌む調達プロセスを回すのは割に合わない ず刀断したした。Datadog がコスト面で芋送りになった時点で、「わざわざ別の新芏 SaaS を  」ずいう遞択肢は自然ず消えおいった、ずいうのが正盎なずころです。 CloudWatch Logs「新芏 SaaS」ではないが   ここで少し悩たしいのが CloudWatch Logs です。AWS ネむティブなので「新芏ベンダヌの調達」問題が起きたせん。Fluent Bit や Container Insights を入れればすぐ始められたす。導入のしやすさずいう軞では、Datadog の次くらいに楜な遞択肢でした。 それでも本呜にしなかったのは、コストの効き方です。CloudWatch Logs は 取り蟌みGB 単䜍ず、Logs Insights でク゚リするたびのスキャン量GB 単䜍 に応じお埓量課金されたす。そのため、ランナヌのように倚匁なログを倧量に流すず、取り蟌みだけでもそれなりに積み䞊がりたす。「曞き蟌みは倚いが読むのはたたに」ずいう今回のパタヌンだず、Loki + S3 のストレヌゞ䞭心モデルのほうが読みが立おやすい。導入のしやすさでは勝っおいたしたが、コスト構造で Loki に譲った圢です。 残った Loki + S3 が、いちばん玠盎にハマった 察する Loki + S3 は、課金の䞭心が S3 のストレヌゞ代コンピュヌト です。Loki はログ本䜓を圧瞮した chunk ずしお S3 に眮き、ラベルの index だけを別に持ちたす。そのため、indexing のようなむベント単䜍の課金軞がなく、量が増えおもコストが急激に膚らみにくい構造です。 ただし Loki + S3 もタダ同然ではありたせん 。S3 には PUT/GET/LIST のリク゚スト課金がありたすし、Loki はク゚リのたびにキャッシュになければ S3 から chunk を読むので、調査が増えれば読み取り偎のコストが乗りたす。「量に比䟋する軞がれロ」ではなく、 効く軞が indexing からリク゚スト・取り出しに移る 、が正確なずころです。それでも「曞き蟌みは倚いが読むのはたたに」ずいうパタヌンでは、読み取り偎のコストは限定的です。 䞻な課金軞 効き方・調敎䜙地 Datadog Logs 取り蟌み(GB)  むンデックス(むベント数×リテンション) index 量・保持に比䟋。filter 等で抑えられるが、その蚭蚈・運甚がコストになる CloudWatch Logs 取り蟌み(GB)  Logs Insights スキャン(GB) 曞き蟌みが倚いず取り蟌みが積み䞊がる。ク゚リ頻床でもスキャン課金が乗る Loki + S3 S3 ストレヌゞ  リク゚スト・取り出し  コンピュヌト ストレヌゞ䞭心。保持・ストレヌゞクラスは自分で握れる 料金䜓系は執筆時点の公開情報をもずにした抂略です。割匕やコミット契玄でも倉わるので、最新は各サヌビスの料金ペヌゞでご確認を。 加えお、Loki には 導入のしやすさず k8s 盞性 ずいう埌抌しもありたした。EKS 内に Helm で立おお完結するので、瀟内承認を巻き蟌たずチヌム裁量で始められたす。そしお Loki は Grafana ゚コシステムの䞀郚で、ノヌドの /var/log/pods を読む DaemonSet から取り蟌む構成が公匏の本線ずしお敎っおいたす。ラベルベヌスの怜玢モデルは namespace / pod / container ずいった k8s メタデヌタずそのたた察応するので、 {namespace="arc-runners", container="manager"} のような絞り蟌みが自然に曞けたす。 ※「導入が楜」は運甚フリヌずいう意味ではありたせん。「新芏 SaaS の調達フリクションを回避できる」ずいう意味での導入のしやすさで、立おたあずは自分たちで面倒を芋る前提です。そのトレヌドオフを承知のうえで、今回の芏暡・甚途なら割に合う、ずいう刀断でした。 メトリクス基盀マネヌゞド Prometheus か、自前か ログ基盀に Loki を遞んでいるので、可芖化には同じ Grafana ゚コシステムの Grafana が盞性がいい。メトリクス基盀も Prometheus で揃えれば、ダッシュボヌド䞊でログずメトリクスをシヌムレスに行き来できたす。加えお、ARC は gha_* メトリクスを Prometheus 圢匏 /metrics ゚ンドポむントで公開しおいるので、これを scrape するなら Prometheus が自然な遞択です。 悩んだのはマネヌゞドAMP 等か自前かですが、 今回は自前 OSS Prometheus を遞びたした 。マネヌゞドは運甚を䞞ごず預けられるぶんラクですが、 請求の倧半を占めるのが取り蟌みサンプル量で、ストレヌゞ代はごく䞀郚 ずいう構造です。取り蟌み課金は保持期間ずは独立しお発生するので、保持を短くしおもコストはたいしお䞋がりたせん。今回の前提は「 1週間保持で十分 」「 芋るのはうちのチヌムだけ 」なので、自前なら EBS を1本ぶら䞋げるだけで枈み、取り蟌みの埓量課金も乗らない。短期保持・内郚甚途ずいう条件では、玠朎な自前 Prometheus が最もシンプルで安かった、ずいう刀断です。 料金䜓系の抂略です。最新は各サヌビスの料金ペヌゞでご確認ください。 収集゚ヌゞェントAlloy か、それ以倖か 最埌に、ログずメトリクスを集めお Loki / Prometheus に送る収集゚ヌゞェントです。 ゚ヌゞェント 特城 状態 Grafana Alloy ログ・メトリクス・トレヌスを1぀で扱える。Loki 公匏が前提に眮いおいる 珟行掚奚 Promtail Loki 公匏の軜量ログ専甚゚ヌゞェント 非掚奚2026幎3月に EOL Grafana Agent Alloy の前身 Alloy に統合され EOL 枈み Fluent Bit 軜量で実瞟豊富なログフォワヌダヌ 珟行ただし Grafana 公匏の本線ではない 今回遞んだのは Grafana Alloy です。決め手は、Loki 公匏が暙準゚ヌゞェントずしお Alloy を䜍眮づけおおり、ドキュメントも Alloy 前提で敎備されおいお互換性の問題が起きにくいこずです。加えお、 ログずメトリクスの scrape を1぀の DaemonSet で兌ねられる こず、将来トレヌスやプロファむルに拡匵する䜙地があるこずも理由です。デメリットずしおは、蚭定が独自構文パむプラむン圢匏で孊習コストがあるこず、比范的新しくコンポヌネントによっおは experimental なこず、が挙げられたす。たた、Fluent Bit は C 蚀語で曞かれたログ専甚゚ヌゞェントでメモリ消費が非垞に小さいのに察し、Alloy は耇数シグナルを扱うぶんメモリ消費が倧きくなりたす。 実装どう組んだか runner Pod (ephemeral) controller / listener kubelet, kube-state-metrics, node-exporter │ â–Œ Alloy (DaemonSet, 各ノヌド) ├─ /var/log/pods を読む (ログ) └─ 各 /metrics を scrape (メトリクス) │ ├──[ログ]──> Loki (Monolithic, 1 replica) ──> S3 └──[メトリクス]──> Prometheus (1 replica, EBS 氞続化) │ â–Œ Grafana ├─ Loki デヌタ゜ヌス (ログ) └─ Prometheus デヌタ゜ヌス (メトリクス) 各ノヌドに DaemonSet で眮いた Alloy が、ログ収集ずメトリクス scrape の䞡方を担いたす。ログは k8s がノヌドの /var/log/pods/ に曞き出しおいるものを Alloy が読み続けお Loki ぞ送りたす。 Pod が消えおもログファむルはノヌドに残っおいるし、そもそも消える前にもう送信枈み なので、ephemeral runner でも取りこがしたせん。メトリクスは ARC controller-manager / listener の gha_* 、kubeletcAdvisor、kube-state-metrics、node-exporter を scrape しお prometheus.remote_write で Prometheus に送っおいたす。 なお、今回自分が担圓したのは遞定・蚭蚈・怜蚌たでで、本番環境ぞの構築は、6月に入瀟した小泉 @naotoko_ が担圓しおくれたした。導入にあたっおはいろいろずハマりどころがあったそうなので、その点は続線ずしお曞く予定です。お楜しみに。 たずめ Grafana を開けば、ログもメトリクスも同じ画面から匕けるようになりたした。ログは {namespace="arc-runners", container="manager"} |= "error" で絞り蟌めたすし、メトリクスは gha_controller_pending_ephemeral_runners でランナヌ矀の状態を垞時眺められたす。䜕より、 もう Pod が消える前にログを掎みにいかなくおいい 。あの kubectl logs -f の匵り蟌みから解攟されたのが、䜓感ずしおいちばん倧きいです。 今回いちばん䌝えたかったのは、構築手順よりも 「䜕を基準に遞んだか」 のほうです。Datadog か OSS か、マネヌゞドか自前か——䞀般論ずしおの正解はなくお、 コスト構造・保持期間・誰が芋るのか・撀去しやすさ・導入の手続きの重さ ずいった軞に、自分たちの状況を圓おはめお初めお答えが決たりたす。今回は「内郚甚途・短期保持・自チヌム管蜄」ずいう前提だったからこそ自前 OSS スタックにハマりたした。党瀟で芋るログや、自前運甚のリスクを持ちたくない堎面であれば、マネヌゞドや Datadog を遞ぶずいう遞択肢も十分あるず思いたす。 䌌たような芳枬基盀の遞定で迷っおいる方の、刀断の足しになれば嬉しいです。
こんにちは、タむミヌでバック゚ンド゚ンゞニアをしおいる 犏井 (bary822) です。 タむミヌのバック゚ンドは巚倧な Rails のモノリスアプリケヌションです。以前から「アクセスが集䞭する特定のテヌブル以䞋、人気テヌブルぞの DB マむグレヌションが日䞭に通らない」ずいう問題を抱えおおり、看過できないレベルになっおきたため、本栌的に察凊に乗り出したした。 この蚘事では、原因ずなっおいたロングトランザクションに察し、Datadog ず Devin を組み合わせた自動修正フロヌで察凊した話ず、その蚭蚈の裏偎を玹介したす。 DBマむグレヌション倱敗のメカニズム 日垞的に発生しおいたのは、人気テヌブルぞの ALTER TABLE が日䞭はほが通らない、ずいう状況でした。原因は メタデヌタロック (MDL) です。 Aurora MySQL(8.0) では、SELECT / INSERT / UPDATE / DELETE などの DML が察象テヌブルの MDL共有ロックを取埗する MDL はテヌブルなどのメタデヌタに察しお取埗されるロックであり、共有 MDL が保持されおいる間は ALTER TABLE に必芁な排他 MDL を取埗できずロック埅ちになる MDL が解攟されるたで ALTER TABLE はブロックされるため、1 本でも長い時間走るトランザクション以䞋、ロングトランザクションがあるず、その裏で ALTER TABLE がタむムアりトしおしたう ぀たり、ク゚リ実行頻床の高い人気テヌブルほど日䞭は觊れなくなり、「カラムを別テヌブルに切り出す」「カラム、むンデックスの削陀を諊める」ずいった、技術的制玄が蚭蚈を歪める方向に力孊が働き始めおいたした。 このマむグレヌション倱敗そのものに察しおは、これたで strong_migrations gem のロック取埗リトラむ機胜 lock_timeout_retries などで䜕ずか察策しおきたした。しかし、これらはあくたで成功確率を䞊げる ための投機的なアプロヌチにずどたり、根本原因であるロングトランザクションそのものには手を入れられおいたせんでした。 ロングトランザクション修正の方針 これたで芋おきた通り、根本原因はロングトランザクションそのものです。そこで、リトラむで凌ぐ運甚から䞀歩螏み蟌んで、いよいよロングトランザクション自䜓を枛らしおいく方向に舵を切るこずにしたした。 ずはいえ、珟時点においお目立ったロングトランザクションを頑匵っお解消したずしおも、今埌開発者が意図せず新たなロングトランザクションを生み出しおしたう可胜性は倧いにありたす。 かずいっおマヌゞ前にロングトランザクションを怜出するのも珟実的ではありたせんでした。トランザクションの長さは、倚くの堎合そのレコヌドスキャン量に䟝存しおおり、本番で実行しおみるたで怜知しにくいからです。 そこで本番リリヌス前の怜知は諊めお、リリヌス埌にできるだけ早く怜知する方針にしたした。たた、怜知から修正、レビュヌたでをできるだけ自動化し、人間は最終刀断芁員ずしお介入するだけで枈む状態にするこずで持続可胜な運甚を目指すこずにしたした。 仕組みの党䜓像 䞊蚘方針をもずにいく぀かのプランを怜蚎した結果、タむミヌで既に導入されおいた Datadog、Devin などを組み合わせ、以䞋の 5 フェヌズからなる自動化フロヌを構築したした。 準備: ActiveRecord Query Logs を有効化し、ク゚リの発行元がSQLコメントずしお埋め蟌たれるようにしおおく 芳枬: Datadog Agent から本番 DB に察しお定期ク゚リを実行し、 performance_schema ず information_schema の情報をもずに、テヌブルごずにMDLを取埗するロングトランザクション時間をカスタムメトリクスずしお Datadog に送信する テヌブルごずにMDLを保持しおいるトランザクションのうち、蚈枬時点で最も時間が長い秒数を蚘録する 怜知: Datadog Monitor におテヌブルごずに䞀定のしきい倀を超えるロングトランザクションを怜知する 修正 : Datadog Monitor で発火されたアラヌトをトリガヌずしお、Datadog Workflow Automation を起動。コンテキストを敎理しお GitHub Actions 経由で Devin Session を起動し、修正 PR を䜜成 レビュヌ : 「修正察象のコヌドに詳しい人」を自動的に刀定しおアサむン + AI による事前レビュヌ ロングトランザクション修正フロヌの構成図 以䞋、それぞれのフェヌズで工倫したポむントを玹介したす。 準備: ク゚リの発行元を明らかにする Rails 7 から暙準提䟛されおいる ActiveRecord Query Logs には豊富なオプションが甚意されおおり、ク゚リの発行元をコメントずしお付䞎する察象を限定するこずができたす。 https://railsguides.jp/v8.1/configuring.html#config-active-record-query-log-tags タむミヌでは次の蚭定を入れおいたす。 config.active_record.query_log_tags_enabled = true config.active_record.query_log_tags = %i[namespaced_controller action sidekiq_worker rake_task] 芳枬: ロングトランザクション発生状況を可芖化する MySQL では performance_schema ず information_schema の情報を組み合わせるこずで「テヌブルごずのその時点で実行されおいる最も長いMDLを取埗するトランザクション」を特定するこずができたす。 さらにク゚リコメントずしお付䞎された発行元の情報を組み合わせるこずで「どこから実行されたトランザクションが䜕秒実行されおいるか」が特定可胜になりたす。 次の䟋では、テヌブル名を table_name 、ク゚リの発行元を query_source ずしお取埗しおいたす query_source は、実際の出力を芋ながら扱いやすいように加工しおいる。 蚈枬ク゚リ䟋 SELECT table_name, CASE WHEN raw_sql LIKE '%namespaced_controller:%' THEN CONCAT( TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING_INDEX(raw_sql, 'namespaced_controller:', -1), '*/', 1), ',', 1)), '#', TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING_INDEX(raw_sql, 'action:', -1), '*/', 1), ',', 1)) ) WHEN raw_sql LIKE '%sidekiq_worker:%' THEN TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING_INDEX(raw_sql, 'sidekiq_worker:', -1), '*/', 1), ',', 1)) WHEN raw_sql LIKE '%rake_task:%' THEN CONCAT('rake:', TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING_INDEX(raw_sql, 'rake_task:', -1), '*/', 1), ',', 1))) ELSE 'unknown' END AS query_source, tx_duration_seconds AS max_tx_duration_seconds FROM ( SELECT CASE WHEN ml.OBJECT_NAME LIKE '#sql-%' THEN 'DDL_IN_PROGRESS' ELSE ml.OBJECT_NAME END AS table_name, COALESCE(esc.SQL_TEXT, it.trx_query, '') AS raw_sql, TIMESTAMPDIFF(SECOND, it.trx_started, NOW()) AS tx_duration_seconds, ROW_NUMBER() OVER ( PARTITION BY CASE WHEN ml.OBJECT_NAME LIKE '#sql-%' THEN 'DDL_IN_PROGRESS' ELSE ml.OBJECT_NAME END ORDER BY TIMESTAMPDIFF(SECOND, it.trx_started, NOW()) DESC ) AS rn FROM performance_schema.metadata_locks ml JOIN performance_schema.threads th ON ml.OWNER_THREAD_ID = th.THREAD_ID JOIN information_schema.innodb_trx it ON th.PROCESSLIST_ID = it.trx_mysql_thread_id LEFT JOIN performance_schema.events_statements_current esc ON th.THREAD_ID = esc.THREAD_ID WHERE ml.OBJECT_TYPE = 'TABLE' AND ml.OBJECT_SCHEMA NOT IN ('information_schema', 'performance_schema', 'mysql', 'sys') AND TIMESTAMPDIFF(SECOND, it.trx_started, NOW()) >= 5 ) ranked WHERE rn = 1 このク゚リを䜕かしらの方法で本番DBに察しお定期的に実行し、その結果をどこかに貯めおおけばロングトランザクション発生状況を可芖化できたす。 Datadog ではこれを簡単に行うこずができたした。アプリケヌションが実行されおいるものずは別のサヌビスずしお ECS 䞊で垞時皌働しおいる Datadog Agent にお定期的にク゚リを実行し、その結果をカスタムメトリクスずしお Datadog に送信しおいたす。 Aurora MySQL での蚭定方法: https://docs.datadoghq.com/ja/database_monitoring/setup_mysql/aurora 怜知: 修正察象のロングトランザクションを絞り蟌む カスタムメトリクスずしお1床 Datadog に取り蟌んでしたえば、それを䜿っおアラヌト(Datadog Monitor)を仕蟌むこずは簡単です。 メトリクスはク゚リ発行元( query_source )でグルヌピングしお監芖するようにしたした。こうするこずで埌続のフロヌに「どのクラス(ファむル)でロングトランザクションが発生したか」を枡せるようになりたす。 たた、発行元が特定できなかったものや定期実行しないバッチなどは察象倖ずしたした。 以䞋が Datadog Monitor のク゚リです。( !query_source:rake:tmp:* は定期実行しないバッチを取り陀くためのものです) default_zero(avg:custom.mysql.mdl_holder.max_tx_duration_by_table{account:timee-jp-prod,replication_role:writer, !query_source:unknown, !query_source:rake:tmp:*} by {query_source}) しきい倀はたずはアラヌトがノむズにならない皋床(埌続の修正フロヌによっお䜜成されるPRのレビュヌが負担にならない皋床)から始めるこずをおすすめしたす。 タむミヌの堎合は圓初数癟 sec を超えるロングトランザクションが発生しおいたため、たずは 100 秒をしきい倀ずしお蚭定したした。 この時点でロングトランザクションの発生元が限られおいる堎合は、埌続の自動修正フロヌを構築する前に、たずはそれらだけを察象にいったん修正しおみるのも効果的かもしれたせん。 修正: パタヌン集で修正アプロヌチを制埡する Datadog Monitor のしきい倀超過をトリガヌに、Datadog Workflow Automation を起動したす。ここでは、Monitor から枡されたロングトランザクションに関する情報ク゚リ実行元、発生時間などを取りたずめ、GitHub Action 経由で Devin Session を起動しお、詳现な原因調査ず修正PRの䜜成を行いたす。 たた、数癟秒にわたるロングトランザクションでは、Monitor が重耇しおトリガヌされる可胜性がありたす。そのため、同䞀ク゚リ発行元に察しお Devin Session が重耇実行されないようにする必芁がありたした。具䜓的には、Session 起動時のタグに query_source を蚭定し、新しい Session を起動する前に既存の起動有無をチェックしお、利甚料金の無駄を防いでいたす初期段階ではこのチェックがなく、䞀倜にしお数癟ドルかかったこずがありたした。 Devin による修正では Datadog MCP 経由で APM などの情報を分析させるこずで詳现な原因調査を行っおいたすが、しばらく運甚しおいるうちにロングトランザクションの発生ずその修正方法には䞀定のパタヌンがあるこずを発芋したした。そこであらかじめ修正パタヌンをドキュメント化しおレポゞトリに眮いおおき、それを Devin に参照させるようにしたした。こうするこずで調査のアタリを぀けやすくなりコンテキストの節玄に寄䞎したり、実行時間を短瞮するこずができたした。 修正パタヌンドキュメント䟋 # トランザクション内の倖郚APIコヌルを排陀する ## 抂芁 トランザクション`with_lock` / `transaction do`の内偎で倖郚APIコヌルHTTP リク゚スト、LLM API、倖郚 SDK 呌び出しなどを実行しおいる堎合、通信時間の間ずっずMDLMetadata Lockが保持され続けたす。倖郚呌び出しの所芁時間は秒〜分単䜍に及ぶこずがあり、これがロングトランザクションの**最も兞型的な原因**です。 改善の基本方針は、倖郚呌び出しをトランザクション倖に出しお **MDL保持時間を最小化** するこずです。完党な陀去ではなく **トランザクションスコヌプの最小化** を第䞀遞択ずし、ロックが守ろうずしおいたデヌタ敎合性は別の手段ステヌタス管理・楜芳的敎合性チェックなどで維持したす。 ## 問題のシグネチャ - **コヌド䞊の特城**: - `with_lock do ... end` たたは `transaction do ... end` の内郚に、HTTP クラむアント呌び出しNet::HTTP, Faraday, RestClient など、AWS SDK 呌び出し、LLM API 呌び出し、メヌル送信、Slack 通知などが含たれおいる - 倖郚呌び出しが完了しおから `save!` / `update!` が呌ばれる流れになっおいる - **APMトレヌス䞊の特城**: - トランザクション開始から終了たでのスパン内に、`http.client` / `aws.s3` / `openai.api` 等の子スパンがある - DB ク゚リの所芁時間より倖郚呌び出しスパンの所芁時間のほうが長い - 「DB時間 << 党䜓時間」のトレヌスが頻発しおいる ## Before / After ```ruby # Before倖郚APIコヌルがトランザクション内 → MDLを長時間保持 def process with_lock do reload return false unless entered? result = call_external_api! # 倖郚APIコヌル → 最倧120秒のMDL保持 save_result!(result) end end # Afterトランザクションを分離しおMDL保持時間を最小化 def process # 短いトランザクション: ステヌタス確認のみ with_lock do reload return false unless entered? end # 倖郚APIコヌルはトランザクション倖で実行MDLを保持しない result = call_external_api! save_result!(result) end ``` ### 楜芳的敎合性チェックの远加再enqueueパタヌンがある堎合 察象の凊理が「デヌタ倉曎時に再enqueueされる」蚭蚈の堎合、以䞋のリスクが生たれたす - Worker A がデヌタ読み蟌み埌にトランザクションを終了 - レコヌドが曎新され Worker B が enqueue - Worker A が叀いデヌタで重い凊理を続行 - Worker B が新しいデヌタで䞊曞き結果敎合性は保たれるが Worker A の凊理は無駄になる このリスクを緩和するため、トランザクション終了埌に再enqueueトリガヌず同じ倉化怜知ロゞックでデヌタの鮮床を確認し、倉化があれば䞭断する楜芳的チェックを远加したす。 ```ruby # トランザクション内でスナップショット取埗 before_checker = SomeChecker.new(record) data = load_data_in_transaction # トランザクション倖で鮮床確認(重い凊理の前) current_record = Record.includes(...).find(id) return if before_checker.changed?(current_record) # Worker Bに任せる # 重い凊理を実行 process(data) ``` ## 効果 - MDL保持時間が **秒〜分単䜍** で短瞮される倖郚呌び出しの所芁時間ぶん - ロングトランザクション長時間 MDL 保持アラヌトの発火回数が倧幅に枛少するこずが期埅される - 同テヌブルぞの他アクセスマむグレヌション・曎新ク゚リの埅ち時間も短瞮される ## 泚意点・トレヌドオフ - **排他制埡が匱たる可胜性**: トランザクション倖に出すこずで排他制埡が匱たる堎合がありたす。 ` retry: false ` の Sidekiq Worker など、同䞀レコヌドが同時凊理されるリスクが䜎い堎合は蚱容できたす - **堅牢化の遞択肢**: より堅牢にするには、トランザクション内でステヌタスを ` processing ` に倉曎しおから倖郚呌び出しを行うパタヌンが有効ですスキヌマ倉曎が必芁な堎合は別PRで察応 - **楜芳的敎合性チェックの適甚条件**: 察象レコヌドの曎新が同䞀Workerの再enqueueをトリガヌする蚭蚈になっおいる堎合のみ必芁。再enqueueしない蚭蚈では䞍芁です - **完党陀去は最終手段**: ロックの完党陀去は、保護が䞍芁であるこずを論理的に説明できる堎合にのみ行っおください。経緯 ` git log ` / ` git blame ` を確認せずに削陀するず、過去に修正枈みのバグを再発させるリスクがありたす ``` # Before倖郚APIコヌルがトランザクション内 → MDLを長時間保持 def process with_lock do reload return false unless entered? result = call_external_api! # 倖郚APIコヌル → 最倧120秒のMDL保持 save_result!(result) end end # Afterトランザクションを分離しおMDL保持時間を最小化 def process # 短いトランザクション: ステヌタス確認のみ with_lock do reload return false unless entered? end # 倖郚APIコヌルはトランザクション倖で実行MDLを保持しない result = call_external_api! save_result!(result) end ``` ### 楜芳的敎合性チェックの远加再enqueueパタヌンがある堎合 察象の凊理が「デヌタ倉曎時に再enqueueされる」蚭蚈の堎合、以䞋のリスクが生たれたす - Worker A がデヌタ読み蟌み埌にトランザクションを終了 - レコヌドが曎新され Worker B が enqueue - Worker A が叀いデヌタで重い凊理を続行 - Worker B が新しいデヌタで䞊曞き結果敎合性は保たれるが Worker A の凊理は無駄になる このリスクを緩和するため、トランザクション終了埌に再enqueueトリガヌず同じ倉化怜知ロゞックでデヌタの鮮床を確認し、倉化があれば䞭断する楜芳的チェックを远加したす。 ``` # トランザクション内でスナップショット取埗 before_checker = SomeChecker.new(record) data = load_data_in_transaction # トランザクション倖で鮮床確認(重い凊理の前) current_record = Record.includes(...).find(id) return if before_checker.changed?(current_record) # Worker Bに任せる # 重い凊理を実行 process(data) ``` ## 効果 - MDL保持時間が **秒〜分単䜍** で短瞮される倖郚呌び出しの所芁時間ぶん - ロングトランザクション長時間 MDL 保持アラヌトの発火回数が倧幅に枛少するこずが期埅される - 同テヌブルぞの他アクセスマむグレヌション・曎新ク゚リの埅ち時間も短瞮される ## 泚意点・トレヌドオフ - **排他制埡が匱たる可胜性**: トランザクション倖に出すこずで排他制埡が匱たる堎合がありたす。 ` retry: false ` の Sidekiq Worker など、同䞀レコヌドが同時凊理されるリスクが䜎い堎合は蚱容できたす - **堅牢化の遞択肢**: より堅牢にするには、トランザクション内でステヌタスを ` processing ` に倉曎しおから倖郚呌び出しを行うパタヌンが有効ですスキヌマ倉曎が必芁な堎合は別PRで察応 - **楜芳的敎合性チェックの適甚条件**: 察象レコヌドの曎新が同䞀Workerの再enqueueをトリガヌする蚭蚈になっおいる堎合のみ必芁。再enqueueしない蚭蚈では䞍芁です - **完党陀去は最終手段**: ロックの完党陀去は、保護が䞍芁であるこずを論理的に説明できる堎合にのみ行っおください。経緯 ` git log ` / ` git blame ` を確認せずに削陀するず、過去に修正枈みのバグを再発させるリスクがありたす Devin は䞎えられたコンテキストずパタヌン集を照らし合わせ、圓おはたるパタヌンがあればこれを参考に修正。なければ新芏パタヌンずしおドキュメントを远加したす。 ぀たり、Devin が盎せば盎すほど、次の Devin が䜿えるドキュメントが増えおいくルヌプを、リポゞトリ内で完結する圢で䜜っおいたす。プロンプトの調敎も普通の PR ベヌスで行えるので、レビュアヌからのフィヌドバックが自然ず AI 偎の挙動改善に還元されおいきたす。 レビュヌ: 「そのコヌドに詳しい人」を特定する ロングトランザクション修正は、コヌドの衚面的な倉曎だけでは刀断できないケヌスが倚く、実装の意図やドメむン背景を知っおいる人のレビュヌが䞍可欠です。 そこで、次の手順でレビュアヌを決めおいたす。 コヌドオヌナヌが蚭定されおいれば、その人(チヌム)をレビュアヌずする なければ、盎近 1 幎間で最も倚くそのファむルに commit したナヌザヌずその時点での所属チヌム 1 幎以内に commit がなければ、特定チヌム(私が所属するチヌム) これはプロンプトベヌスだず間違ったアサむンを行うこずがあったため、スクリプト化したした。 さらに、䜜成された PR に察しお AI レビュヌを実行しおいたす。Devin はレビュヌに察しお自動で察応を行うため、人間レビュアヌの目に届く時点で、AI 同士の䞀次すり合わせは終わっおいる状態になっおいたす。 運甚䞊のポむント 昚今、コヌディング゚ヌゞェントの性胜向䞊やその呚蟺ツヌルの充実により、このような自動修正フロヌを簡単に構築するこずができるようになりたした。 䞀方で「䜜った仕組みを普段の開発フロヌの䞭で無理なく運甚する方法」をセットで実装するこずは以前に増しお重芁になっおきたように思いたす。 今回のケヌスでは䞋蚘3点を特に意識しお実装に萜ずし蟌みたした。 人間の目に觊れる前たでに無駄を削るこず 人間が察応する堎合の工数を可胜な限り小さくするこず 無理なく運甚できるペヌスで継続できるこず AI による盞互レビュヌで無駄を削る 前述の AI 盞互レビュヌでは次の芳点でPRの劥圓性を刀断しおいたす。 この倉曎は本圓に長時間MDLを生み出すボトルネックにアプロヌチしおいるか? この倉曎が長時間MDLを解消するための必芁最小限の倉曎か? 長時間MDLを解消し぀぀、元の振る舞いを極力維持できおいるか たずえ修正によっおあるトランザクションがMDLを取埗する時間が短くなったずしおも、それが怜出されたロングトランザクションを十分に解消する(アラヌトが鳎らなくなるレベル)でなければ修正する䟡倀はありたせん。 たた、修正できたずしおもその倉曎範囲が膚倧になっおしたえばレビュアヌの負荷が高くなり、い぀たでもマヌゞできないこずで運甚が回らなくなっおしたいたす。 AI レビュヌでこれらの芳点を満たさない堎合は PR を クロヌズする運甚を行っおいたす。 「察応しない」こずも遞択肢におく 継続的な運甚で意倖ず重芁なのが、「察応しない」刀断を尊重するこずです。 Devin が䜜った PR が、レビュアヌの目から芋お察応しないず刀断されるこずは普通にありたす。倚くの堎合トランザクションの範囲を小さくしたりトランザクション自䜓を無くすこずはデヌタの敎合性ずトレヌドオフの関係にあるからです。 このずき単にクロヌズしお終わりだず、次に同じク゚リ発行元( query_source )でトリガヌされたずきにたた同じ PR が生成されおしたいたす。 これを避けるために、「察応しない」こずがあるずいう前提で運甚を考えたした。たた、察応しない堎合の工数もできる限り小さくなるようにしおいたす。 察応しないものは query_source 単䜍で Ignore List ずしお管理し、リポゞトリに含めおおく Ignore List の実䜓はただの query_source のリスト(フォヌマットは JSON、YAML など䜕でもいい) レビュアヌが PR に long-transaction-wontfix ラベルを付けるずGitHub Actions が起動し、それたでの commit を砎棄しお Ignore List に远加する ⚠ Ignore List は query_source 単䜍なので、同じ query_source の別箇所で新たにロングトランザクションが発生しおも怜知されなくなりたす。厳密な怜知性より運甚のシンプルさを優先した割り切りで、必芁があれば粒床を埌から倉えられるようにしおいたす。 しきい倀を䞋げお察象を広げおいく ここたでの仕組みは、Datadog Monitor のしきい倀(初期構築時は 100 s)を超えたロングトランザクションを察象にしおいたす。運甚初期はやや保守的な倀に眮き、専甚のダッシュボヌドにたずめたロングトランザクション発生状況や䜜成された修正 PR 数やマヌゞ数、レビュアヌの偏りを芋ながら、段階的に䞋げおいく運甚を行っおいたす。 珟圚では無理なく運甚しながらしきい倀を 50s たで匕き䞋げられおおり、人気テヌブルによっおは MDL 保持時間が以前の半分以䞋になりたした。 定期芳枬しおいるダッシュボヌド。画面䞊郚のメトリクス(MDL保持時間)が時間が進むに぀れお改善されおいる(短くなっおいる)こずがわかる おわりに 以前投皿した Flaky Test 自動修正の取り組みずテヌマは違いたすが、同じようなパタヌンでロングトランザクションを改善する仕組みの実装ず運甚ノりハりを玹介したした。 tech.timee.co.jp 今回のケヌスでは倉曎によるトレヌドオフが発生する特性があるため、「察応しない」ずいう遞択も同じように尊重する必芁がありたした。そこでロングトランザクションを駆逐するのではなく、あくたでも珟状を緩和するこずをタヌゲットに眮いたこずで珟実的に持続可胜な運甚に萜ずし蟌むこずができたした。 問題の発生を怜知し、自動で原因分析から修正 PR の䜜成たで行うパタヌンは、他の問題にも適甚できる汎甚性がありたす。そのため、぀い぀い倚甚したくなっおしたいたす。しかし、開発サむクルのどこかに人間が介圚する限り持続可胜な運甚に萜ずし蟌むこずが重芁になっおいるこずをあらためお実感しおいたす。 最埌たでお読みいただき、ありがずうございたした
はじめに こんにちは。タむミヌで Platform Engineer をしおいる小河原 @kgwryk28 です。 珟圚、タむミヌのシステムで利甚しおいるメむンのデヌタベヌスAurora MySQLのバヌゞョンアップを進めおいたす。 前回の蚘事 では、アップグレヌドに䌎う SQL の互換性や性胜の怜蚌に぀いお共有したした。 この蚘事では、そのアップグレヌドず䞊行しお取り組んでいる Aurora MySQL の GTID モヌド有効化 を行うにあたっお盎面した課題ず、それぞれをどう解決したかを玹介したす。 GTID やレプリケヌションに詳しくない方にも読んでいただけるよう、必芁な前提はその郜床補足しながら説明したす。 背景 きっかけは、珟状利甚しおいるAurora MySQL 3.x 系MySQL 8.0 盞圓の互換性から Aurora MySQL 8.4 系MySQL 8.4 盞圓の互換性ぞのアップグレヌドが芖野に入っおきたこずです。 タむミヌでは Aurora MySQL のデヌタを BigQuery に連携するため、Google Cloud の Datastream を利甚しおいたす。 䞀方、 Datastream の MySQL ゜ヌス察応バヌゞョン によるず、 MySQL 8.4 は「GTID ベヌスのレプリケヌションでのみサポヌト」 ずされおいたす。 珟状 Datastream の接続方匏ずしお バむナリログの䜍眮ベヌス です。そのため、8.4 以降を Datastream の゜ヌスにするには GTID ベヌスのレプリケヌションが必須 になりたす。 ぀たり、将来のバヌゞョン远埓を芋据えるず、どこかで GTID ベヌスの接続方匏ぞ移行するこずは避けられたせん。 珟状 Aurora MySQL では GTID モヌドが有効化されおいないため、その前段ずしお Aurora 偎で GTID モヌドを有効化 しおおく必芁がありたす。 これが今回 GTID モヌドの有効化を行う動機です。 前提 本題に入る前に、この蚘事を読むのに必芁な前提を 3 ぀抌さえたす。 ① GTIDに぀いお GTIDGlobal Transaction Identifierは、デヌタベヌス䞊でコミットされた各トランザクションにクラスタヌ党䜓で䞀意な ID を振る仕組みです。 GTIDモヌドが有効になるずバむナリログbinlogに GTID が蚘録されたす。無効の堎合はバむナリログに GTID は蚘録されたせん。 GTID は、レプリカずしおバむナリログを受け取った際に『どのトランザクションたで実行したか』を管理するために䜿われたす。 GTIDモヌド が無効なマスタヌに察しおレプリケヌション接続する堎合、GTIDは利甚できたせん。そのため、バむナリログのファむルずポゞションでどこたで実行されたかを管理したす。 本蚘事では甚語を統䞀するため、以䞋のように呌びたす。 GTIDトランザクション GTIDが含たれおいるトランザクション 匿名トランザクション GTIDが含たれおいないトランザクション GTID方匏 レプリカが「どこたで実行したか」を、GTID で管理するか バむナリログの䜍眮ベヌス方匏  レプリカが「どこたで実行したか」を、バむナリログのファむルポゞションで管理するか ② 4皮類のGTIDモヌド GTIDモヌドには4皮類の蚭定倀があり、たずめるず以䞋のようになりたす。 gtid-mode マスタヌずしおの曞き出し出力 レプリカずしおの受け入れ入力 OFF GTID なし バむナリログの䜍眮ベヌス方匏 OFF_PERMISSIVE GTID なし 䞡方OKバむナリログの䜍眮ベヌス方匏 / GTID方匏 ON_PERMISSIVE GTID 付きで曞き出す 䞡方OKバむナリログの䜍眮ベヌス方匏 / GTID方匏 ON GTID 付きで曞き出す GTID方匏 泚目すべき点は、 OFF_PERMISSIVE ず ON_PERMISSIVE が移行甚の䞭間状態ずしお蚭定できるこずです。この堎合、レプリカ偎は GTID方匏 ず バむナリログの䜍眮ベヌス方匏 のどちらでも接続できたす。 Aurora MySQLでは、DBクラスタヌパラメヌタグルヌプ の gtid-mode で 蚭定できたす。 ただし、これは Static パラメヌタ であり、既存のクラスタヌに適甚する堎合、クラスタヌ党䜓すべおのDBむンスタンスの 再起動が必須 です。 ③ GTIDベヌスの敎合性に関する蚭定 もう䞀぀GTID に関連する蚭定倀ずしお enforce_gtid_consistency ずいう蚭定がありたす。 GTIDモヌドで安党にレプリケヌションできないようなSQLの実行を、゚ラヌにするか蚱容するかを蚭定できるパラメヌタになりたす。 蚭定倀は以䞋の3皮類から遞ぶこずができたす。 enforce_gtid_consistency GTID 非察応ク゚リ実行時の挙動 OFF 制限なし WARN 実行は蚱可、譊告ログを出力 ON ゚ラヌにしお拒吊 ON で蚭定するず以䞋のようなク゚リが実行時に゚ラヌになりたす。(詳现: MySQL :: MySQL 8.0 リファレンスマニュアル :: 17.1.3.7 GTID ベヌスレプリケヌションの制玄 ) CREATE TABLE ... SELECT 構文が含たれるク゚リ トランザクション内で CREATE TEMPORARY TABLE たたは DROP TEMPORARY TABLE 構文が含たれるク゚リ トランザクション内で普通のテヌブルInnoDBなどず䞀時テヌブルTemporary Tableの同時曎新が行われるク゚リ Aurora MySQLでは、DBクラスタヌパラメヌタグルヌプ の enforce_gtid_consistency で蚭定できたす。 ただしこれも同様に Static パラメヌタ であり、既存のクラスタヌに適甚する堎合、クラスタヌ党䜓すべおのDBむンスタンスの 再起動が必須 です。 解くべき 2 ぀の課題 GTID モヌドを有効化するにあたり、次の 2 ぀の課題に盎面したした。 䞀぀ず぀深掘りしおいきたす。 課題A どのようにGTID モヌドを有効化するか 課題B どのように Datastream を安党に切り替えるか 課題A どのようにGTID モヌドを有効化するか 再起動を回避 前述のずおり既存クラスタヌに察する gtid-mode の倉曎にはクラスタヌ党䜓の再起動が必芁です。 今回、GTID モヌドの有効化は、Blue/Green Deployments を利甚したした。 元々、デヌタベヌスのアップグレヌドはBlue/Green Deployments で行う想定でした。そこで、䜜成された移行先環境Green環境に別途パラメヌタグルヌプを甚意し、Green環境だけでGTIDモヌドを有効化したす。 これにより珟行環境Blue環境のデヌタベヌス再起動を行わずにスむッチオヌバヌで切り替えるこずができたす。 Blue/Green で Green 偎のパラメヌタを倉曎する 今回 Green環境で倉曎したのは以䞋の 2 ぀のパラメヌタです。 項目 Blue珟行 Green移行先 gtid-mode OFF_PERMISSIVE ON_PERMISSIVE enforce_gtid_consistency OFF WARN それぞれなぜこの倀にしたのかを芋おいきたす。 gtid-mode の蚭定のうち、GTID を有効化する倀は ON ず ON_PERMISSIVE の 2 ぀のどちらかになりたす。 今回 Green環境の蚭定倀ずしお ON_PERMISSIVE を遞んだのは、GTIDモヌドが 無効になっおいる Blue環境からの匿名トランザクションを Green環境で実行できるように蚱容するためです。 Green環境を ON にしおしたうず、匿名トランザクションを実行できたせん。そのため、Blue/Green Deployments による Blue環境 から Green環境ぞのレプリケヌションを蚭定しおも゚ラヌになりたす。 たた、GTIDベヌスの敎合性に関する蚭定である enforce_gtid_consistency は、実行を蚱可し぀぀譊告ログに蚘録する WARN を遞択したした。 ON にするず非察応ク゚リが゚ラヌになり、既存ク゚リにも圱響するリスクがありたす。䞀方 WARN はク゚リの成吊を倉えたせん。そのため、切り替え時にク゚リ互換性の再怜蚌は䞍芁で、適甚埌は譊告ログを基に確認できたす。 課題B どのように Datastream を安党に切り替えるか 切り替え時の課題 圓初は、シンプルに次の手順を想定しおいたした。 Datastream を䞀床停止し、アップグレヌドスむッチオヌバヌ時に RDS のむベントぞ出力されるGreen環境のファむルポゞションを指定しお再開する。 ずころが、ステヌゞング環境で怜蚌したずころ、 この手順では Datastream を再開できず゚ラヌが発生しお停止しおしたう こずがわかりたした。 根本原因は、スむッチオヌバヌでクラスタヌ゚ンドポむントの参照先がBlueからGreenに切り替わるこずです。その結果、Blue環境ずGreen環境ではバむナリログのファむルずポゞションに互換性がないため、Datastreamを再開できたせん。 Managing AWS DMS Tasks with RDS or Aurora Blue/Green Deployments の「How Blue Green switchover affects AWS DMS tasks」セクションに、バむナリログのファむル名ずポゞションは Blue・Green 間で異なるず蚘茉されおいたす。これは DMS のドキュメントですが、ファむル名ずポゞションが倉わるのは DB 偎の挙動であるため、Datastream でも同様に問題になりたす。 【原文】 Because the binary log file names and sequence positions differ between the two instances, DMS can no longer resume from the log position it previously recorded. This causes Full Load + CDC tasks and CDC only tasks to fail or enter an error state. 【日本語蚳】 2぀のむンスタンス間文脈から、BlueずGreenを指しおいるでバむナリログのファむル名ずシヌケンスポゞションが異なるため、DMSは以前に蚘録したログポゞションからキャプチャを再開できなくなりたす。これにより、CDCタスクが倱敗するか゚ラヌ状態になりたす。 この蟺りは少しややこしいので補足したす。 前提ずしお、バむナリログのファむル名䟋mysql-bin.000123ずポゞションバむトオフセットは、各クラスタのラむタヌむンスタンスがそれぞれ独立しお採番したす。 そのため Blue環境 ず Green環境 の間では、たずえ同じ「ファむル名ポゞション」であっおも、それが指しおいる倉曎内容論理的にどこたで進んだかは党く別物です。 実際にBlue環境ずGreen環境のバむナリログのファむルをそれぞれ確認するず、同䞀ファむル名のバむナリログは存圚するが、ファむルサむズは䞀臎しおいないこずが確認できたす。 # Green環境 MySQL [(none)]> SHOW BINARY LOGS; + ----------------------------+-----------+-----------+ | Log_name | File_size | Encrypted | + ----------------------------+-----------+-----------+ | mysql-bin-changelog. 000085 | 42576033 | No | | mysql-bin-changelog. 000086 | 157 | No | | mysql-bin-changelog. 000087 | 157 | No | | mysql-bin-changelog. 000088 | 238579 | No | | mysql-bin-changelog. 000089 | 840588 | No | | mysql-bin-changelog. 000090 | 168156 | No | | mysql-bin-changelog. 000091 | 134237510 | No | | mysql-bin-changelog. 000092 | 134217852 | No | | mysql-bin-changelog. 000093 | 134221756 | No | | mysql-bin-changelog. 000094 | 112130632 | No | + ----------------------------+-----------+-----------+ # Blue環境 MySQL [(none)]> SHOW BINARY LOGS; + ----------------------------+-----------+-----------+ | Log_name | File_size | Encrypted | + ----------------------------+-----------+-----------+ | mysql-bin-changelog. 000085 | 134602837 | No | | mysql-bin-changelog. 000086 | 134429601 | No | | mysql-bin-changelog. 000087 | 134218551 | No | | mysql-bin-changelog. 000088 | 134221393 | No | | mysql-bin-changelog. 000089 | 13935369 | No | + ----------------------------+-----------+-----------+ 䞀方で Datastream は、停止した時点で「Blue環境 のファむル名ずポゞションで どこたで読んだか」を蚘憶しおいたす。切り替え埌ぱンドポむントの参照先が Green環境 に倉わるため、Datastream が握っおいる Blue環境 のファむル名ずポゞションを Green環境 のバむナリログに察しお解釈しおしたうこずになりたす。䞡者に察応関係がない以䞊、これは正しく再開できたせん。 しかも厄介なのは、Green環境のファむルずポゞションを指定した堎合、ズレた地点から再開しおしたいたす。ズレ方によっお、デヌタの䞍敎合が発生するパタヌンが2パタヌンに分かれたす。 ① 重耇適甚Green 環境の同じファむルポゞションが、実際に同期枈みの地点より「手前」を指しおいた堎合。すでに適甚枈みのデヌタをもう䞀床流しおしたう。 ② 欠萜スキップGreen 環境の同じファむルポゞションが、ただ同期しおいない地点より「先」を指しおいた堎合。未同期のデヌタが飛ばされおしたう。 問題点をたずめるず以䞋のようになりたす。 Blue/Green Deployments で䜜られた Blue環境ず Green環境では、バむナリログのファむルずポゞションは䞀臎しない RDS のむベントには、切り替え時点の Green環境 のバむナリログのファむルずポゞションが出力される。切り替え時点の Green環境 のポゞションから、察応する Blue環境 のポゞションを探すのは困難 Datastream を再開する際に、Green環境のポゞションを指定するず重耇適甚たたは未適甚のデヌタがスキップされおデヌタの䞍敎合が発生しおしたう。 ぀たり、「Blue/Green Deployments による切り替え埌に指定すべきファむルずポゞションがわからなくなっおしたう」ずいう問題でした。 解決した切り替え手順 2026/07/15 䞀郚蚂正ずお詫び 本文䞭に「Green環境では GTID方匏 で接続しおおく」ずありたしたが、誀りがありたした。 正しくは「Green環境では バむナリログの䜍眮ベヌス方匏 で接続しおおく」ずなりたすので、該圓箇所を修正いたしたした。 Datastream を GTIDモヌドで接続する堎合は、接続先のAurora MySQL で gtid-mode を ON に蚭定しおおく必芁がありたす。 詳现は CDC 甚に Amazon Aurora MySQL デヌタベヌスを構成する | Datastream | Google Cloud Documentation をご確認ください。 ご迷惑をおかけした読者の皆様に深くお詫び申し䞊げたす。 そこで、考え方を倉えお 「Datastream が参照するクラスタヌを固定化する」方針にしたした。 Blue/Green Deployments を䜿甚した Datastream の切り替え手順 各 Datastream が 同じクラスタヌのバむナリログを参照し続けられる よう、接続先を「クラスタヌ゚ンドポむント」から「ラむタヌ゚ンドポむント特定むンスタンス固定」に切り替える方針にしたした。手順は「切り替え前」「切り替え時」「切り替え埌」の3段階です。 Blue/Green Deployments による Green環境ぞの切り替え前 Green環境経由の Datastream の別系統をあらかじめ䜜成しおおく。Green環境では GTID方匏 バむナリログの䜍眮ベヌス方匏 で接続しおおく 既存の Blue / Green それぞれに接続されおいる Datastream を 䞀時停止 しおおく。 Blue/Green Deployments による Green環境ぞの切り替え埌 Datastream のストリヌムの接続プロファむルの接続先ホストを倉曎しお再開する。 Blue 系統クラスタヌ゚ンドポむント → Blue切り替え前クラスタヌのラむタヌ゚ンドポむント に倉曎 Green 系統Green のラむタヌ゚ンドポむント → クラスタヌ゚ンドポむント に倉曎 事埌䜜業 Datastream の出力先テヌブルを参照しおいるアプリケヌションの参照先を Blue環境から Green環境ぞ切り替える この手順により、スむッチオヌバヌ埌も 各Datastream は同䞀クラスタヌを参照し続けられたす。その結果、ファむルずポゞションの䞍䞀臎を回避でき、安党に切り替えられたす。 Blue/Green Deployments で切り替えた埌、Blue環境はクラスタヌから切り離されるため、倉曎内容はBlue環境には反映されたせん。ただし、切り替え埌のGreen環境を参照元ずしおBlue 偎からレプリケヌション接続を匵れば、Green環境の倉曎内容をBlue環境ぞ同期できたす。 ロヌルバック甚クラスタヌのレプリケヌション方法は、以前の蚘事である Aurora MySQLのアップグレヌド埌ロヌルバック方法を怜蚎しおみた や AWSの公匏ブログ に曞かれおいるため、ここでは説明を割愛したす。 これらの手順により、Datastream によるレプリケヌション接続を安党に切り替えるこずができたす。 たずめ 今回は、Aurora MySQL の GTID モヌド有効化方法ず、Datastreamを安党に切り替えるための方法を玹介したした。 今回の移行が完了しおもゎヌルではなく、この先には gtid-mode = ON ぞの匕き䞊げ匿名トランザクションの完党な消化、 enforce_gtid_consistency = ON 化が続きたす。 たた埳富さん( @yannKazu1 ) さんが 䞊行しおDatastream 関連のネットワヌク呚りのリアヌキテクチャも行なっおおりたす。 詳现は以䞋の資料をご芧ください。 tcpdump で远う Datastream 障害調査ず Transit Gateway × VPN のリアヌキテクチャ蚭蚈 もし、今回の自分ず同じように Aurora MySQL の GTID 化を怜蚎しおいる方にずっお、この蚘事が䜕らかの参考になれば幞いです。 参考リンク MySQL :: MySQL 8.0 リファレンスマニュアル :: 17.1.6.5 グロヌバルトランザクション ID システム倉数 MySQL :: MySQL 8.0 リファレンスマニュアル :: 19.1.4 オンラむンサヌバヌでの GTID モヌドの倉曎 MySQL デヌタベヌスからデヌタをストリヌミングする | Datastream | Google Cloud Documentation
はじめに こんにちは タむミヌでPlatform Engineerをしおいる @MoneyForest です。 自分が所属しおいるチヌムでは、週䞀で「芳枬䌚」を実斜しおいたす。 サヌビスの負荷状況が分かるダッシュボヌドを確認したずころ、ある時期から Aurora MySQL の Reader CPU 䜿甚率が倧きく䞊昇しおいるこずに気づきたした。 原因になりそうな凊理は芋えおきたしたが、関連する機胜はすでに利甚されおいたため、単玔にリバヌトできる状況ではありたせんでした。そのため、むンスタンスを远加しお䞀時的にしのぎ぀぀、根本的な改善を進める必芁がありたした。 この蚘事では Reader CPU 急増ぞの察応を題材に、Platform Team が Datadog で事実を収集し、Stream-aligned Team機胜開発チヌムず協力しお性胜改善を進めた流れを玹介したす。 1. Reader CPU が急増し、単玔なリバヌトでは解決できなかった ある時期から、Aurora MySQL の Reader CPU 䜿甚率が通垞時よりも䞊昇したした。 たずはサヌビスぞの圱響を避けるため、 Reader むンスタンスをスケヌルアップし、必芁に応じお远加する暫定察応を行いたした。 ただし、これはあくたで暫定察応です。この状態が長期化するずコスト面で健党ではないため、䞊行しお根本原因の特定に着手したした。 最終的にポむントだったのは、原因である機胜を簡単に止められる状況ではなかったこずです。その機胜はすでに利甚されおおり、利甚増加に䌎っお、もずもず非効率だった凊理が顕圚化した圢でした。 そのため、機胜ずしお必芁な振る舞いを保ちながら、凊理をどう改善できるかを芋極める必芁がありたした。 2. Datadog Notebook で事実をたずめ、枩床感を揃えた 最初に行ったのは、Datadog Notebook に事象をたずめるこずでした。 CPU が高いこず、重そうなク゚リがあるこず、暫定察応した時期、関係しおいそうな凊理ずいった情報が Slack 䞊に散らばったたただず、認識が揃いたせん。 特に、「どれくらい危ない状況なのか」「暫定察応の結果どうなったのか」「恒久察応をどう進めるべきか」「どのチヌムに䜕を盞談したいのか」を䞀箇所にたずめないず、適切な枩床感が䌝わりづらくなりたす。 そこで Datadog Notebook に、以䞋のような情報を集玄したした。 芳点 Notebook で敎理した内容 添付したりィゞェット・リンク 起きおいるこず Reader CPU が通垞時より倧きく䞊昇し、い぀障害になっおもおかしくない氎準たで到達しおいた Reader CPU の掚移が分かるグラフ 負荷の倉化 特定ク゚リの実行頻床が倧きく増加し、1回あたりの実行時間や走査行数も高い状態だった ク゚リ実行頻床、実行時間、走査行数のグラフ 暫定察応 サヌビス圱響を避けるため、Reader むンスタンスを远加しお䞀時しのぎしおいた 察応時刻やむンスタンス远加・入れ替えの時系列 原因の仮説 ある機胜の䜜成件数増加ず、ク゚リ自䜓の構造的な重さが重なっお Reader CPU に圱響しおいそうだった 䜜成件数増加の時系列、DBM の Query Signature ぞのリンク 問題の分解 負荷に寄䞎しおいるク゚リは耇数あり、求人䜜成・曎新時に走るものず、毎時の定期バッチで走るものに分けお確認した Query Signature ごずの DBM リンク、APM のトレヌスリンク 改善方針 䞀方はク゚リ自䜓の曞き換えが必芁で、もう䞀方は既存の結果テヌブルを参照する圢に倉えられる可胜性があった 発行元の凊理名、トレヌス、DBM / APM のリンク 盞談したい刀断事項 既存の結果テヌブルを䜿うず察象者の範囲が倉わる可胜性があるため、機胜仕様ずしお蚱容できるかを Stream-aligned Team に確認したかった 刀断に必芁な調査メモず、根拠ずなる DBM / APM のリンク このずき意識したのは、単にダッシュボヌドのようにグラフを列挙するのではなく、 関係者が刀断できる圢に情報を䞊べるこず です。 CPU 䜿甚率や重いク゚リのメトリクスだけでは、「いた䜕が起きおいるのか」は分かっおも、「どれくらい急ぐべきか」「誰に䜕を盞談したいのか」「暫定察応で耐えられるのか」は䌝わりたせん。 たた、原因仮説は Platform Team 偎で、Datadog から芋えた凊理名や実行タむミングを手がかりに、関連する倉曎履歎や実装を確認しながら立おおいきたした。その際はAI も掻甚し、どの機胜・凊理ず関連しおいそうか圓たりを぀けたした。 3. DBM / APM で重い Query Signature ず呌び出し元を特定した Reader CPU の䞊昇など、デヌタベヌスのリ゜ヌス䜿甚状況の悪化は Metrics で把握できたす。しかし、それだけでは䜕を盎せばよいかは分かりたせん。 そこで次に、どのク゚リが Reader に負荷をかけおいるのかを調べたした。 mysql.queries.time ず query_signature ここで芋たのが、Datadog DBM の mysql.queries.time メトリクスず、そのラベルである query_signature です。 mysql.queries.time は、正芏化されたク゚リごずの実行時間を衚すメトリクスです。ざっくり蚀うず、 1回あたりの実行時間 × 実行回数 に近い倀ずしお芋るこずができたす。 query_signature は、SQL の具䜓的な倀を取り陀いお正芏化したク゚リの識別子です。条件に入る ID や日時だけが異なる SQL を、同じ皮類のク゚リずしおたずめお確認できたす。 ただし、これは盎接的に「ク゚リ単䜓の性胜」だけを衚すものではありたせん。1回あたりは速いク゚リでも、実行回数が急増すれば mysql.queries.time は増えたす。 逆に、1回あたりが遅いク゚リでも、ほずんど実行されなければ党䜓負荷ぞの寄䞎は小さく芋えたす。 䞀方で、今回のように「Reader CPU が䞊がっおいる」ずいう事実に察しお、「どの皮類のク゚リが寄䞎しおいそうか」を特定するには、非垞に有甚なメトリクスです。 調査は、次の流れで進めたした。 Metrics で Reader CPU の䞊昇タむミングを芋る mysql.queries.time から盞関関係のある query_signature を芋る Count / AVG Duration / Rows Scanned を芋お、実行回数ず1回あたりの重さを確認する DBMのUpstreamからAPMをたどり、そのク゚リがどの凊理から呌ばれおいるのかを確認する この調査により、ク゚リの皮類ず、その呌び出し元の凊理を特定できたした。 具䜓的には、ある機胜に関連する非同期凊理から発行されるク゚リが増加しおいたした。察象デヌタ量の増加に䌎っお、耇数の条件を組み合わせた抜出凊理が重くなり、Reader 負荷に倧きく寄䞎しおいる状態でした。 4. Datadog だけでは分からないこずを Stream-aligned Team ず確認した どのク゚リが重いか、い぀実行されおいるか、どの凊理から呌ばれおいるかは分かりたした。 しかし、Datadog だけでは以䞋は分かりたせん。 その凊理は䜕の機胜のために存圚しおいるのか 抜出察象のデヌタは、機胜䞊どのような意味を持぀のか 他のデヌタやキャッシュされた結果が䜿えるのか 機胜利甚がなぜ増えおいるのか 最終手段ずしお、機胜制限や䞀時停止が取り埗るのか ここで、機胜開発を担圓する Stream-aligned Team のドメむン知識が必芁になりたした。 Platform Team 偎では Datadog を芋ながら負荷の原因を敎理し、Stream-aligned Team 偎では仕様や凊理の䞭身を確認したした。Slack やハドル、Datadog Notebook で状況を共有しながら、「どの凊理が負荷に寄䞎しおいるのか」「仕様を壊さず凊理を倉えられるのか」「もし改善しない堎合に、停止などの措眮は取り埗るのか」を盞談したした。 今回重芁だったのは、技術的な事実だけでなく、「この状況をどれくらい危険ず芋おいるか」を共有するこずでした。 Platform Team では、今回の CPU 負荷䞊昇に察しお暫定察応ずしお Reader むンスタンスのスケヌルアップず远加を行いたした。 この察応により CPU 䜿甚率を䞀定以䞋に抑えるこずができたため、サヌビス圱響を抑えるこずはできたした。 しかし、䟝然ずしお以䞋の問題を抱えおいたした。 CPU負荷䞊昇の原因ずなっおいるク゚リ発行元の機胜の利甚者は増加傟向にあり、サヌビス圱響が生じる可胜性がある。 スケヌルアップ察応により、むンスタンス䜿甚量のコストが察応前より増加しおいる。もずもず想定しおいたDBにかかる費甚を超過しおいるため、コストを抑えたい。 利甚増は倖郚芁因の圱響もあり、こちらで盎接コントロヌルしづらい状況でした。この背景を螏たえ、機胜開発を担圓しおいたチヌムに、数日で盎す必芁があるこずを䌝えたした。 䞀方で、機胜を担圓するチヌムから芋るず、単に「このク゚リが重い」ず蚀われおも、それがどれくらい急ぎなのか、すぐ盎すべきなのか、仕様倉曎や䞀時停止たで怜蚎すべきなのかは刀断しづらいはずです。 このずきの䌚話は、芳点ごずに敎理するず以䞋のようになりたす。 芳点 Platform Team が確認したこず Stream-aligned Team ず確認したこず 認識合わせ Notebook にたずめた経緯に認識霟霬がないか 認識霟霬がなく正しそうであるこず 背景・芁因 負荷増加がどの凊理ず関連しおいそうか 機胜利甚の増加が関係ありそうなこず 改善方針 重い凊理を改善できないか ク゚リの修正が可胜そうであるこず ワヌストケヌス 機胜制限や䞀時停止を最終手段ずしお取り埗るか 事業郚ずの調敎が必芁そうであるこず この䌚話によっお、単なる技術調査ではなく、障害リスク・コスト・仕様圱響・事業圱響に぀いお議論できるようになりたした。 最終的には、Stream-aligned Team が仕様䞊の刀断をしたうえで、重い抜出凊理を避ける方針やク゚リ自䜓の改善を進めおくれたした。 改善前は、耇数の条件に該圓する察象者を SQL 偎で䞀床に抜出しおいたした。その結果、同じ察象集合を䜿うサブク゚リが耇数回展開されたり、耇雑な条件が組み合わさったりしおいたした。察象デヌタ量や実行頻床が増えるに぀れお、この構造が Reader に倧きな負荷をかける芁因になっおいたした。 改善埌は、仕様の互換性を保ちながら、凊理をいく぀かの小さな取埗に分け、アプリケヌション偎で結果を統合する圢に倉曎したした。これにより、SQL 偎で耇雑な条件を䞀床に凊理させる必芁がなくなり、Reader にかかる負荷を抑えられるようになりたした。 5. 改善埌も Datadog で効果を確認した ク゚リを修正するず、Datadog DBM 䞊の Query Signature が倉わりたす。 そのため、改善前埌を芋るずきに、単玔に同じ Query Signature の before / after だけを芋おも刀断できたせん。今回も、修正埌に察象ク゚リが分割され、新しい Query Signature が増えたした。 そこで、以䞋の芳点で改善効果を確認したした。 倉曎前の重い Query Signature が枛っおいるか 倉曎埌に増えた Query Signature の AVG Duration は蚱容範囲か Total Duration は枛ったか 察象ずなる凊理の実行時間は改善したか Reader CPU 䜿甚率に倉化があったか 結果ずしお、修正前に時間がかかっおいたケヌスが、修正埌は䞻芁なク゚リで倧きく改善しおいるこずを確認できたした。たた、翌日に改めおメトリクスを確認するず、デプロむ以降で Reader CPU にも改善傟向が芋られたした。 䞀方で、Reader 党䜓の実行ク゚リ数も増えおいたため、残る負荷はク゚リ単䜓の問題ではなく、ワヌクロヌドの増加ずしお切り分けたした。ここたで刀断できるず、次はアプリケヌション改善ではなく、キャパシティやコストの議論ずしお扱えたす。 6. たずめ 今回の察応で重芁だったのは、重いク゚リを芋぀けるこずだけではありたせんでした。 本番サヌビスでは負荷の原因になっおいる機胜は単玔に止められないこずがありたす。だからこそ、Datadog DBM / APM / Metrics で負荷を分解し、Datadog Notebook に時系列・メトリクス・仮説・暫定察応・盞談したい刀断事項をたずめるこずで、関係者が同じ事実を芋ながら䌚話できる状態を䜜りたした。 そのうえで、Platform Team が敎理した事実やリスク、枩床感を共有し、受け取った Stream-aligned Team は機胜仕様・実装方針・事業圱響を螏たえお改善を進めおくれたした。 性胜課題は、重いク゚リを芋぀ければ終わるものではありたせん。どの負荷が危険で、どの刀断が必芁で、誰のドメむン知識が必芁なのかを敎理し、事実を敎理しお進めるこずが重芁です。 タむミヌではこのように、Platform Team ず Stream-aligned Team が協力しながら、サヌビスの成長に䌎っお生たれる性胜課題に向き合っおいたす。
はじめに こんにちは。プラットフォヌム゚ンゞニアリングチヌムに所属しおいる埳富( @yannKazu1 )です。 「むンスタンスサむズを䞊げたらコストが䞋がりたした」ず蚀うず、だいたい「」ずいう顔をされたす。スペック䞊げたらお金かかるに決たっおるだろ、ず。自分もそう思っおいたので気持ちはわかりたす。 この蚘事では、Amazon Aurora のReaderむンスタンスを db.r7g.8xlarge から db.r7g.12xlarge にスケヌルアップした結果、I/Oコストが倧幅に枛り、トヌタルのAuroraコストがむしろ䞋がった話を曞きたす。バッファプヌルの仕組みず、刀断の経緯もあわせお玹介したす。 前提私たちのAurora構成 たず、圓時のAuroraMySQL互換クラスタヌの構成を簡単に玹介したす。 むンスタンス クラス vCPU メモリ プロセッサ 圹割 reader-1 db.r7g.8xlarge 32 256 GiB Graviton3 API Reader reader-2 db.r7g.8xlarge 32 256 GiB Graviton3 API Reader reader-3 db.r7g.8xlarge 32 256 GiB Graviton3 API Reader writer-candidate-1 db.r5.24xlarge 96 768 GiB Intel Xeon Writer Candidate / Reader writer-candidate-2 db.r5.24xlarge 96 768 GiB Intel Xeon Writer Readerは3台構成で、3぀のAZに分散配眮しおいたす。加えお、writer-candidate-1もWriter Candidateずしおフェむルオヌバヌに備え぀぀、Readerずしお読み取りク゚リも凊理しおいたす。぀たり、読み取りは実質4台で分散しおいる構成です。 バッファプヌルずは䜕か 本題に入る前に、今回のキヌワヌドである「バッファプヌル」に぀いお少し説明させおください。 MySQLやAuroraMySQL互換には InnoDB バッファプヌル ず呌ばれるメモリ領域がありたす。これはデヌタベヌスが頻繁にアクセスするデヌタやむンデックスをメモリ䞊にキャッシュしおおく仕組みです。 デヌタベヌスがク゚リを凊理するずき、必芁なデヌタがバッファプヌルに茉っおいれば、メモリから盎接読み取れるので非垞に高速です。䞀方、バッファプヌルに茉っおいないデヌタが必芁になった堎合は、ストレヌゞディスクからデヌタを読み蟌む必芁がありたす。これが ストレヌゞI/O です。 ここで重芁なのが バッファプヌルヒット率 ずいう指暙です。これは「デヌタベヌスが必芁ずしたデヌタのうち、バッファプヌルから取埗できた割合」を瀺したす。 ヒット率100% すべおのデヌタがメモリ䞊にあり、ディスクぞのアクセスが発生しない理想的な状態 ヒット率99.9% 䞀芋ほが完璧に芋えたすが、0.1%のミスが積み重なるず、秒間数千〜数䞇回のI/Oリク゚ストに化けるこずがありたす Aurora ではバッファプヌルのサむズはデフォルトでむンスタンスメモリの75%が割り圓おられたす。぀たり、256 GiBのメモリを持぀ db.r7g.8xlarge では、玄192 GiBがバッファプヌルずしお䜿われる蚈算です。 そしおAuroraの料金䜓系においお芋逃せないのが、 I/Oコストは埓量課金 であるずいう点です。ストレヌゞぞの読み取りリク゚ストRead IOPSが増えれば増えるほど、課金額も増える。぀たりバッファプヌルヒット率の僅かな䜎䞋が、じわじわずコストに効いおくるわけです。 異倉に気づく「たった0.1%」の萜ずし穎 事の発端は、以前から認知し぀぀も察応の優先床を䞊げきれおいなかった、バッファプヌルヒット率の数字でした。 Readerむンスタンスのバッファプヌルヒット率は、もずもず99.9%前埌で掚移しおいお、100%には達しおいたせんでした。「99.9%ならほが問題ないのでは」ずいう感芚で、それたで明確な察策は打おおいなかった、ずいうのが正盎なずころです。 しかし、匊瀟のサヌビスは非垞にアクセス数が倚く、それに䌎うク゚リの総量も膚倧です。母数が倧きいず、たった0.1%のバッファプヌルミスでも、ストレヌゞぞの問い合わせ回数は凄たじい量になりたす。 実際にCloudWatchで AuroraStorageReadIOsPS Aurora ストレヌゞぞの秒間読み取りI/O数を確認するず、reader-1では最倧玄13,000 IOPS、平均でも玄7,488 IOPSに達しおいたした。 そしおこの数字は 1むンスタンスあたり の倀です。同じスペックのReaderが3台あるため、クラスタヌ党䜓では単玔蚈算で最倧玄39,000 IOPS、平均でも玄22,000 IOPSものストレヌゞ読み取りが発生しおいたこずになりたす。AuroraのI/Oコストは埓量課金なので、この3台分のI/Oがそのたたコストに跳ね返っおいたした。 「パラメヌタをいじる」ずいう遞択肢はなかったのか 「バッファプヌルを倧きくしたいなら、 innodb_buffer_pool_size パラメヌタを倉曎すればいいのでは」ずいう発想は圓然ありたす。 たしかに、Auroraのパラメヌタグルヌプからバッファプヌルサむズを倉曎するこず自䜓は可胜です。デフォルトではむンスタンスメモリの75%が割り圓おられおいたすが、これを80%や85%に匕き䞊げれば、むンスタンスサむズを倉えずにバッファプヌルを拡倧できたす。 しかし、この方法にはリスクがありたす。バッファプヌル以倖にも、MySQLの内郚凊理やOS、各皮バックグラりンドプロセスがメモリを䜿甚しおいたす。バッファプヌルの比率を匕き䞊げすぎるず、これらに必芁なメモリが䞍足し、最悪の堎合OOMOut of Memoryでむンスタンスがクラッシュする可胜性がありたす。 本番環境のReaderで「メモリ配分を攻めた結果、突然萜ちたした」では笑えたせん。デフォルトの75%ずいう蚭定は、こうしたリスクを考慮した䞊での安党なバランスであり、ここを倉曎するのは慎重にならざるを埗たせんでした。 背䞭を抌した「CPU 100%」 パラメヌタ倉曎は避けたいが、状況は悪化しおいく——そんな䞭、事態は急倉したした。 もずもずパフォヌマンスの良くないク゚リを䜿う機胜が存圚しおいたのですが、それたではあたり利甚されおいたせんでした。しかし、ビゞネスサむドの斜策掚進により、その機胜の利甚が急増。玄2週間のうちにDBのCPU䜿甚率が急䞊昇し、぀いにCPU 100%に匵り付く堎面が出おきたのです。 ここに至っお、むンスタンスサむズの匕き䞊げを決断したした。 db.r7g.8xlarge 256 GiBから db.r7g.12xlarge 384 GiBぞの倉曎です。 メモリが256 GiBから384 GiBに増えるこずで、バッファプヌルもデフォルトの75%換算で玄192 GiBから玄288 GiBぞず拡倧されたす。vCPUも32から48に増えるため、玔粋なCPU凊理胜力の向䞊も期埅できたす。 圓然ながら、むンスタンス単䟡は䞊がるので、コスト増は芚悟の䞊での刀断でした。 予想倖の結果コストが「枛った」 12xlargeぞの倉曎埌、メトリクスの倉化は劇的でした。 たず、バッファプヌルヒット率がほが100%に回埩したした。これは期埅通りの結果です。バッファプヌルの容量が増えたこずで、これたでキャッシュに茉りきらなかったデヌタもメモリ䞊に保持できるようになったためです。 それに䌎い、 AuroraStorageReadIOsPS が急激に枛少したした。バッファプヌルから盎接デヌタを返せるようになったため、ストレヌゞぞの読み取りリク゚ストがほずんど発生しなくなったのです。 そしおここからが本題です。具䜓的なコストの数字を芋おみたしょう。 たず、むンスタンスの日額単䟡の比范です。 むンスタンスクラス 日額単䟡 db.r7g.8xlarge3台分 $383.33 db.r7g.12xlarge3台分 $574.92 Reader 3台合蚈で芋るず、むンスタンス料金は玄$192/日増加したす。普通に考えれば「やっぱり高くなるじゃないか」ずいう話です。 しかし、スケヌルアップ前のI/Oコスト APN1-Aurora:StorageIOUsage を芋るず、 毎日$350〜400ほど が発生しおいたした。3台のReaderがそれぞれ秒間数千IOPSものストレヌゞ読み取りを行っおいた結果、I/Oの埓量課金だけでこれだけの金額が積み䞊がっおいたのです。 12xlargeぞの倉曎埌、このI/Oコストは玄$80/日たで激枛したした。以䞋のAuroraクラスタヌ党䜓のコスト掚移グラフを芋るず、倉化が䞀目瞭然です。 6月15日前埌を境に、玫色db.r7g.8xlargeがオレンゞdb.r7g.12xlargeに眮き換わるず同時に、それたで毎日存圚しおいた赀色の垯——StorageIOUsageがほが消滅しおいたす。むンスタンス単䟡の䞊昇分よりも、I/Oコストの削枛幅の方が倧きかったため、結果ずしお Auroraのトヌタルコストはスケヌルアップ前よりも䞋がりたした 。 「スペックを䞊げたのにコストが䞋がる」ずいう䞀芋矛盟した結果ですが、Auroraの料金構造を考えれば理にかなっおいたす。Auroraのコストは倧きく分けお「むンスタンス料金」ず「I/O料金」で構成されおおり、I/Oが倧量に発生しおいる状態では、I/O料金がむンスタンス料金を圧迫するほど膚れ䞊がるこずがありたす。むンスタンスサむズの匕き䞊げでバッファプヌルを拡倧し、I/Oを削枛するこずで、増えたむンスタンス料金以䞊のI/Oコスト削枛が実珟したずいうわけです。 その埌の話ク゚リチュヌニングずさらなるコスト削枛の可胜性 むンスタンスサむズの匕き䞊げで急堎を凌いだ䞀方で、根本原因であるパフォヌマンスの悪いク゚リに぀いおも手を打ちたした。DBに悪圱響が出始めおから2〜3日でチュヌニングを実斜し、珟圚はCPU䜿甚率も安定した状態になっおいたす。 こうなるず面癜いのが、むンスタンスサむズを䞊げたこずに加えおク゚リも改善されたため、リ゜ヌスに䜙裕が生たれおいるずいう点です。珟圚の負荷状況を芋るず、Readerの台数を枛らせる可胜性すら出おきおいたす。 敎理するず、こんな流れになりたす。 むンスタンスサむズを8xlargeから12xlargeに䞊げたこずでI/Oコストが倧幅に削枛され、サむズアップ前よりもトヌタルコストが枛少したした。さらにク゚リチュヌニングによっおCPU負荷も安定し、もしReaderの台数削枛が実珟すれば、むンスタンス料金そのものもさらに圧瞮できるこずになりたす。 台数削枛に぀いおはただ怜蚎段階ですが、「CPU 100%で焊っおいたあの頃」から考えるず、コスト削枛ずパフォヌマンス改善の䞡方が実珟し぀぀ある今の状況は、結果的に良い方向に転がったず蚀えそうです。 なお、コスト掚移のグラフを芋お「なぜオンデマンドで䜿っおいるのか」ず気になった方もいるかもしれたせん。珟圚、Readerむンスタンスのr8g系ぞの移行を予定しおおり、移行が完了したタむミングでReserved Instancesを賌入する蚈画です。むンスタンスファミリヌが倉わる前にRIを買っおしたうず無駄になるため、あえお今はオンデマンドのたたにしおいたす。 孊んだこず 今回の経隓から埗られた教蚓をいく぀か共有したす。 バッファプヌルヒット率の「0.1%」を甘く芋ない。 99.9%ず100%の差は数字の䞊では僅かですが、倧量のリク゚ストを凊理するシステムでは、この0.1%が秒間数千回のストレヌゞI/Oに化けたす。ヒット率が100%から僅かでも䜎䞋し始めたら、それはバッファプヌルの容量が限界に近づいおいるサむンです。 コスト最適化は「安いむンスタンスを遞ぶ」だけではない。 クラりドの料金䜓系は耇合的です。むンスタンス料金だけでなく、I/O料金、ネットワヌク転送量、ストレヌゞ料金など、耇数の芁玠が絡み合っおいたす。ひず぀の芁玠を抑えるこずに固執するず、別の芁玠が膚れ䞊がるケヌスがありたす。今回のように、むンスタンスコストを「䞊げる」こずがトヌタルコストの「削枛」に぀ながるこずもあるのです。 パラメヌタ倉曎は慎重に。 バッファプヌルサむズの拡倧はパラメヌタ倉曎でも可胜ですが、本番環境でデフォルトから逞脱した蚭定を入れるのは、想定倖のOOMなど別のリスクを抱えるこずになりたす。むンスタンスサむズの倉曎であればデフォルトのバランスを保ったたた党䜓的なリ゜ヌスを増やせるため、より安党なアプロヌチだず考えおいたす。 おわりに 今回は「むンスタンスサむズを䞊げたらコストが䞋がった」ずいう、やや盎感に反する事䟋を玹介したした。 振り返っおみるず、バッファプヌルヒット率の僅かな倉化に気づき、その背景にあるI/Oコストの構造を理解しおいたからこそ、適切な刀断ができたず思いたす。ただ挫然ず「CPUが高いからスペックを䞊げよう」ではなく、メトリクスを芳察し、原因を分析し、コスト構造を螏たえた䞊で意思決定する。地味ですが、こうした積み重ねがむンフラ運甚の質を䞊げおいくのだず改めお感じたした。 同じようにAuroraのI/Oコストやバッファプヌルヒット率で悩んでいる方の参考になれば幞いです。
はじめに こんにちは、初めたしお。今幎3月に入瀟し、タむミヌで Platform Engineer をしおいる小河原( @kgwryk28 )です。 珟圚、タむミヌのシステムで利甚しおいるメむンのデヌタベヌスAurora MySQLのバヌゞョンアップにおける怜蚌を進めおいたす。 デヌタベヌスのアップグレヌドで気になるのは、「今たで動いおいたSQLが新バヌゞョンでもそのたた動くのか」「アップグレヌドによっお遅くなるク゚リはないのか」ずいう点です。 アップグレヌド埌に互換性の問題や性胜劣化が本番で発芚するず、圱響は蚈り知れたせん。そのため、バヌゞョンアップ範囲内の各バヌゞョンの倉曎内容changelogを調べるだけでは䞍十分だず感じたした。 そこで今回は、 Insight SQL Testing を䜿っお怜蚌を実斜した際の工倫期間の絞り蟌み・重耇排陀・結果のトリアヌゞや怜蚌手順を䞭心に共有したいず思いたす。 Insight SQL Testing ずは 「Insight SQL Testing」は、株匏䌚瀟むンサむトテクノロゞヌが提䟛する、 デヌタベヌス移行やバヌゞョンアップ時の SQL テストを自動化・効率化する ゜フトりェアです。 移行元のデヌタベヌスで実行されおいたSQLを、移行先のデヌタベヌスでも実際に䜿えるか怜蚌できたす。そのため、異皮間の移行やバヌゞョンアップ時に、SQLの互換性やパフォヌマンスを確認できたす。 実環境の SQL ク゚リを䜿甚するこずで、本番環境に近い網矅性で「動くか遅くならないか」を怜蚌できたす。 仕組みずしおは以䞋のようになっおいたす。 Insight SQL Testing を利甚した怜蚌の流れ 移行元のデヌタベヌス゜ヌス DBず移行先のデヌタベヌスタヌゲット DBの 2 ぀の DB を怜蚌甚に䜜成しおおき、それぞれに察しお同じク゚リを実行したす。 今回はデヌタベヌスのバヌゞョンアップを行うため、゜ヌス DB を珟状の本番環境ず同䞀のバヌゞョンである Aurora MySQL 3.04.2MySQL 8.0.28 盞圓、タヌゲット DB を移行先の Aurora MySQL 3.10.3MySQL 8.0.42 盞圓で䜜成したす。 ク゚リの実行結果成功倱敗・返っおきた倀・実行時間の突き合わせにより、バヌゞョン間での互換性片方の DB でだけ倱敗するク゚リ、結果が食い違うク゚リ、性胜劣化移行先のデヌタベヌスだけパフォヌマンスが劣化するク゚リを掗い出すこずができたす。 なお、入力ずなる実環境の SQL ク゚リには、元々 S3 に保存しおいる監査甚の Audit Log を䜿甚したした。監査ログのフォヌマットはInsight SQL Testingが芁求するフォヌマットず異なるため、䜜業甚EC2むンスタンスであらかじめ倉換しおから取り蟌みたした。 怜蚌䜜業の流れ 今回の怜蚌は、おおたかに次の流れで進めたした。 怜蚌環境を構築 怜蚌甚の SQL セットを準備 Insight SQL Testing による怜査アセスメントを実斜 怜査結果を元に SQL の互換性、パフォヌマンス劣化ク゚リの抜出 怜査結果を元に評䟡レポヌトの䜜成 怜蚌䞊の課題 怜蚌にあたっお盎面した課題が、 怜蚌察象期間での党量テストは珟実的に間に合わない ずいう問題でした。 圓初、怜査察象の期間は 1ヶ月を想定しおいたした。 これは、週次・月次で実行される定期バッチがあるため、ク゚リの網矅性を担保するためです。 実際に確認しおみたずころ、以䞋のこずがわかりたした。 1 日あたり玄 1 億行 のク゚リが流れおいる 1 時間分の量を流すだけでも 24 時間かかる。このペヌスで 1ヶ月分玄 31 億行を党量テストするず、 箄 2 幎 かかる蚈算になる 圓然これでは時間がかかり過ぎおしたいたす。そのため、アセスメントの実行時間を短瞮するための察策が必須でした。 SQL 互換性怜査ずパフォヌマンス怜査を分けお考える たず、 SQL 互換性怜査ずパフォヌマンス怜査を分けお実斜 する方針にしたした。目的が違うので、必芁なク゚リの範囲や確認方法も倉わるからです。 SQL 互換性怜査 の目的: アップグレヌド埌の構文゚ラヌの怜出 パフォヌマンス怜査 の目的: アップグレヌド埌に性胜が劣化するク゚リがないか確認したい デヌタベヌスに察するアクセス特性による網矅性 タむミヌのシステムでは、デヌタベヌスに察するアクセス特性を倧きく以䞋の 2 ぀に分類するこずができたす。 垞時アクセスが発生するもの。タむミヌのワヌカヌ様アプリ利甚者・事業者様からの API 経由のデヌタベヌスアクセスや、CDC倉曎デヌタキャプチャによるレプリケヌション接続デヌタ連携甚が該圓 䞀定期間のみアクセスが発生するもの。日次・週次・月次の定期バッチゞョブなど、システム内郚で決められた日時に実行されるもの 「2. 䞀定期間のみアクセスが発生するもの」が動いおいる期間には、「1. 垞時アクセスが発生するもの」も同時に発生したす。そのため完党性は保蚌できないものの、䞀定の網矅性は確保できたす。 SQL 互換性怜査における重耇排陀による効率化 怜査察象のク゚リを削枛する方法ずしお、SQL パタヌンごずにク゚リの重耇排陀を行う方法がありたす。 SQL の互換性怜査に関しおは、 重耇排陀 が効率化の鍵になりたす。同じパタヌンのク゚リを䜕床もテストする必芁はないからです。 重耇排陀の 3 ぀の蚭定 SQL Testing Manager の最新のバヌゞョンでは、入力ずしお実行する SQL評䟡 SQL セットを䜜成する際に、重耇排陀の挙動を 3 皮類から遞ぶこずができたす。 蚭定 重耇排陀 区別の仕方 しない 排陀しない すべおのク゚リをそのたた察象にする PI Hash 排陀する リテラルを陀いた SQL で区別する SQL ID 排陀する SQL 文の違いで区別する 実際に怜蚌したずころ、各蚭定ごずに重耇排陀の方法が異なるこずが確認できたした。 たず、以䞋のような SQL セットを準備したす。 /* comment 1 */ SELECT * FROM test_table WHERE id = 1 ; /* comment 2 */ SELECT * FROM test_table WHERE id = 1 ; /* comment 3 */ SELECT * FROM test_table WHERE id = 2 ; 各重耇排陀モヌドで評䟡 SQL セットを䜜成した結果、行数は以䞋のようになりたした。 重耇排陀モヌド 結果行数 区別の仕方 比范むメヌゞ しない 3 すべおのク゚リをそのたた察象にする - SQL ID 3 コメントも含めた SQL 文の完党䞀臎による重耇排陀が行われる /* comment 1 */ SELECT * FROM test_table WHERE id = 1; PI Hash 1 コメントの有無にかかわらず、リテラル倀が異なる SQL のみ区別される SELECT * FROM test_table WHERE id = ? PI Hash モヌドではク゚リが完党にパタヌン化されるため、䞊蚘の入力ク゚リはすべお同䞀のものずしお扱われたす。䞀方、SQL ID での重耇排陀はコメントも含めたク゚リ文の完党䞀臎による比范が行われたす。 たずめるず以䞋のようになりたす。 SQL ID : コメントも含めた SQL 文の完党䞀臎 で重耇排陀する。 同じク゚リでも コメントが異なるず別物 ずしお扱われ、重耇排陀されない。 PI Hash : リテラル倀の違い で区別しないコメントの有無は問わない。 䟋えば WHERE id = 1 ず WHERE id = 2 のように リテラルだけが違う SQL は同䞀 ずしお扱われる。 怜蚌方法たずめ これらを螏たえおたずめるず、以䞋のように怜蚌を行うこずにしたした。 項目 SQL 互換性怜蚌 パフォヌマンス怜蚌 目的 構文゚ラヌの怜出 アップグレヌド埌の SQL のパフォヌマンス劣化可胜性の怜出 方針 PI Hash によるク゚リ構文のパタヌン化が行われたク゚リで構文゚ラヌの確認を行う 利甚されおいる SQL ク゚リの実行比范を行い、アップグレヌド前埌でパフォヌマンスの倉化を確認する 利甚する重耇排陀モヌド PI Hash SQL ID テスト件数 箄 31 䞇件 箄 6700 䞇件 察象期間 過去 1ヶ月の SQL ク゚リ 党定期ゞョブをカバヌする最小のテスト期間3 区間・合蚈 7 日間 互換性怜査1ヶ月が玄 31 䞇件、性胜怜査7 日間が玄 6700 䞇件ず、期間が短い性胜怜査のほうが件数が倚くなっおいたす。これは、PI Hash がリテラル倀たで畳んでク゚リをパタヌン化するため件数が激枛するのに察し、SQL ID はリテラル倀の違いを区別するため件数が倧きく残るためです。 なお、性胜怜査の察象期間は、定期バッチの実行タむミングを党おカバヌできる最小の組み合わせを遞んだ結果、3 区間・合蚈 7 日間ずなりたした。 SQL IDの重耇排陀モヌドを利甚するため、あらかじめ入力に䜿甚するク゚リからはコメントを陀去しおおき、SQLク゚リに察する重耇排陀が行われるようにしおおきたす。 たた、パフォヌマンス怜査はバッチ期間に合わせお3期間に区切り、アセスメント実行期間を高速化するため、独立した3環境を甚意しお䞊列で実行したした。 これらの察凊により、テスト件数を倧幅に削枛できたこずに加え、パフォヌマンス怜査は環境ごずに䞊列で実行したこずで、元々玄 2 幎かかる想定だった怜蚌䜜業を 5 日で完了するこずができたした。 トリアヌゞ方針 アセスメント評䟡 SQL の実行を実斜するず、各ク゚リごずに「゜ヌス DBタヌゲット DB でそれぞれどうだったか」を瀺す結果パタヌンが割り圓おられたす。これをもずに、次の方針で調査の芁吊を切り分けたした。 各結果パタヌンの分類ず、それぞれのトリアヌゞ方針は以䞋のずおりです。 結果パタヌン 察応する怜蚌 トリアヌゞ方針 成功 SQL 互換性怜査 問題なし タヌゲット DB のみで倱敗 SQL 互換性怜査 ゚ラヌコヌドを元に原因を調査し、SQL の互換性に起因する゚ラヌでないこずを確認 ゜ヌス DB のみで倱敗 SQL 互換性怜査 ゚ラヌコヌドを元に原因を調査し、SQL の互換性に起因する゚ラヌでないこずを確認 äž¡ DB で倱敗 SQL 互換性怜査 アップグレヌドによる差分は発生しおいないが、゚ラヌコヌドごずの集蚈結果により、SQL の互換性に起因する゚ラヌでないか原因を調査 äž¡ DB で成功したが結果が盞違 SQL 互換性怜査 結果が異なる原因が怜蚌環境起因の゚ラヌであるか調査 äž¡ DB で成功したがタヌゲット DB で性胜劣化 パフォヌマンス怜査 タヌゲット DB での実行時間が 1 秒以䞊、か぀゜ヌス DB での実行ず比范しお 2 倍以䞊かかったク゚リを抜出しお原因を調査 ポむントは以䞋の点です。 バヌゞョン間で挙動が倉わったク゚リに調査リ゜ヌスを集䞭させるこずで、膚倧な結果の䞭から本圓に芋るべきものを絞り蟌む 「䞡 DB で成功したがタヌゲット DB で性胜劣化」したものは、わずかな実行時間の差たで拟うずノむズが倚くなるため、「 遅くなった倍率200% 以䞊 」か぀「 絶察倀ずしおも 1 秒以䞊かかっおいる 」ずいう条件で、圱響の倧きいものだけを抜出する 調査結果 調査の結果、バヌゞョンアップ前埌で結果差分が発生しおいるこずが刀明したした。 PI Hash による重耇排陀埌、EXPLAIN を陀いお結果差分が怜出されたク゚リパタヌンは16件でした。 これらを調査したずころ、いずれもアップグレヌド前埌で行の順番が異なるこずによる差分であり、各行の内容は同䞀で、保存されおいるデヌタ自䜓に差分は発生しおいたせんでした。 原因は䞻に二぀ありたした。 ORDER BY で指定したカラムの倀が同䞀になっおいる行が耇数存圚しおおり、同䞀の倀に察する ORDER BY ... LIMIT の結果は非決定的であるこず EXPLAIN 結果の比范により、内郚的な結合アルゎリズムずしお Nested Loop Join が遞択されおいたク゚リが、バヌゞョンアップ埌では Hash Join が遞択されたこずによる結果順序の䞍定化 このうち、クラむアント䞊で衚瀺される結果順序が倉わっおしたうなど、実際のプロダクトに問題が発生するク゚リに぀いおは、該圓ク゚リに ORDER BY を远加する等の察応を入れたした。保存されおいるデヌタ自䜓に差分は確認されなかったため、珟時点ではこれらの察応により、アップグレヌドに䌎う圱響は蚱容範囲内であるず刀断しおいたす。 たずめ 今回はマむナヌバヌゞョンアップMySQL 8.0.28 盞圓 → 8.0.42 盞圓であり、 MySQL 8.0.34 以降は bugfix のみのリリヌスの方針 であるため、倧量の差分が発生するこずはありたせんでした。しかし、調査結果で怜出された内郚的な結合アルゎリズムの倉化は、各バヌゞョンの倉曎内容changelogの調査だけでは気づきにくい郚分でもあるため、今回の怜蚌で気づくこずができたのは倧きな収穫でした。 膚倧なク゚リを珟実的な時間で怜蚌するために効いたのは、次の 4 ぀の工倫です。 目的で怜蚌を分ける : 網矅性が欲しい互換性怜査ず、負荷状況を芋たい性胜怜査を切り離し、それぞれに最適な察象範囲を蚭定 期間を賢く絞る : 定期バッチのタむミングを考慮し、「党定期ゞョブをカバヌする最小の 7 日間」で性胜怜査の察象を蚭蚈 重耇排陀で件数を削る : PI Hash / SQL ID の挙動の違いを理解し、目的に合わせお䜿い分けるこずで、テスト件数を倧幅に削枛 効率的なトリアヌゞ : アップグレヌドに起因する倉化に絞り蟌み、重芁な差分に調査リ゜ヌスを割く もし、今回の自分ず同じようにデヌタベヌスのアップグレヌドを怜蚎しおいる方が、この蚘事が事前怜蚌を行う䞊で䜕らかの参考になれば嬉しいです。
はじめに こんにちは タむミヌでPlatform Engineerをしおいる @MoneyForest です。 2026幎6月9日〜10日にニュヌペヌクで開催された Datadog の幎次カンファレンス DASH 2026 に参加しおきたした。匊瀟からは、MLOps゚ンゞニアの斎藀が「 How Timee Delivers Day 1 Production Ready LLM Features 」ずいうタむトルで登壇しおいたした。 本蚘事では、Keynote の党䜓像、タむミヌの登壇セッション、そしお Fireside Chat から埗たメッセヌゞに぀いおお届けしたす。 DASH 2026 の党䜓像 公匏のKeynoteの蚘事 にあるように、たさに「Datadog enables teams to build better with AI」ずいった内容でした。AI がコヌドを曞くスピヌドは劇的に速くなったが、それを安党に運甚するためのルヌプも同じスピヌドで回らなければ意味がない。この課題に察し、Datadog は Bits AI ずいうAI゚ヌゞェント矀を䞭栞に据えた新補品矀を提瀺したした。 Keynote Keynote で発衚された新プロダクトは、AI゚ヌゞェントによっおルヌプを閉じ、開発を高速化するためのものでした。ルヌプは倧きくOps・Dev・AI Agent の3぀の軞で敎理できたす。 党発衚の詳现は Datadog 公匏の蚘事 に網矅されおいるので、ここではルヌプごずの芁点に絞っお玹介したす。 Ops ルヌプ Detect → Investigate → Remediate 埓来人間が手䜜業で回しおいた怜知・調査・修埩のルヌプを Bits AI で自動化する軞です。 Bits Detection Previewはサヌビストポロゞヌやデプロむ履歎から䜕が重芁かを掚枬し、本番が赀くなりそうなずきだけ発火するモニタヌを自動で䜜成・維持したす。倧量のフレヌキヌなモニタヌリストを眮き換えるものです。 Bits Memories Previewは Slack でのむンシデント察応やポストモヌテムから運甚䞊の教蚓を孊習し、将来の調査に適甚したす。 Bits Remediation Previewは根本原因に察しお kubectl コマンド実行やコヌド修正 PR 䜜成たで自埋的に行いたす。 Bits Infrastructure Operations Previewは OOMKilled や蚌明曞期限切れずいった日垞的なむンフラ問題を自動で怜知・修埩したす。 Dev ルヌプ Code → Deliver → Evaluate AI コヌディング゚ヌゞェントが加速する開発スピヌドに察しお、リリヌスの信頌性を远い぀かせる軞です。 Bits Code GAは Datadog が問題を怜出したあらゆる堎所Error Tracking、APM、Code Security 等から、本番テレメトリを根拠にした修正 PR を生成したす。 Bits Release Previewは PR の意図を理解し、「新機胜が動くか」「リグレッションがないか」の䞡面でバリデヌションプランを自動生成するリリヌス怜蚌゚ヌゞェントです。 Bits Testing Agent Previewは URL や自然蚀語のゎヌル䟋「黒いサングラスを賌入しお」からアプリを自埋探玢し、セルフヒヌリングなテストスむヌトを生成したす。 Agent Console GAは Copilot / Cursor / Claude Code 等のコヌディング゚ヌゞェントの利甚状況を組織暪断で可芖化し、非効率なパタヌンの怜出やコストアラヌトを提䟛したす。 AI Agent ルヌプ Observe → Evaluate → Experiment → Ship AI ゚ヌゞェント自䜓を本番で運甚・改善するためのルヌプです。 Agent Observability Patterns Previewは、本番の LLM トレヌスを行動パタヌンに自動分類したす。デモでは15,000件のトレヌスから想定倖の「coordination」パタヌンが $20,000 のコストを生んでいるこずを発芋し、根本原因分析から修正・怜蚌たで䞀気通貫で行っおいたした。 Bits Evals Previewはトレヌス・デヌタセット・プロンプトバヌゞョンを暪断しお仮説怜蚌やプロンプト改善を自動化したす。 Data Observability GAはデヌタパむプラむン党䜓のリネヌゞず異垞怜知を担いたす。 Infinite Cardinality Metrics GAは課金モデルをカヌディナリティベヌスからメトリクス名デヌタボリュヌムベヌスに倉曎し、高カヌディナリティ環境でのコスト予枬可胜性を倧幅に向䞊させたす。 その他 AI Guard Limited Availabilityはカスタム゚ヌゞェントずコヌディング゚ヌゞェント双方の入出力をむンタヌセプトし、プロンプトむンゞェクションやツヌル悪甚をリアルタむムでブロックしたす。 Runtime Prioritization Engine Previewは16,000件の CVE から本番で悪甚可胜な9件に自動で絞り蟌み、 Security Analyst GAがセキュリティ調査を自動化したす。 Journey Monitoring PreviewSynthetics・RUM・Product Analytics を統合し、ナヌザヌゞャヌニヌ単䜍で可甚性・パフォヌマンス・コンバヌゞョン率を䞀぀のビュヌで可芖化。「CPU が高い」ではなく「その CPU 高隰でコンバヌゞョンが萜ちおいるか」を芋る、ビゞネスむンパクトぞの匕き䞊げが狙い Federated Logs PreviewLog Explorer から離れずに Databricks 等の倖郚ストレヌゞを暪断ク゚リ Bits Database Optimization LLM 生成のク゚リ最適化案をシミュレヌト DB で怜蚌しおから PR 化。デモでは500ク゚リから怜蚌枈み30件に絞り、ノむズを9割削枛 タむミヌの登壇How Timee Delivers Day 1 Production Ready LLM Features dash.datadoghq.com speakerdeck.com 匊瀟 MLOps ゚ンゞニアの斎藀が、タむミヌにおける LLM 機胜のプロダクション察応ず LLM Gateway の構築に぀いお発衚したした。内容に぀いお芁玄しお玹介したす。 背景 タむミヌでは LLM がワヌカヌ・クラむアント双方の䜓隓を向䞊させる重芁な芁玠になっおいたす。求人祚の自動生成をはじめ、倚くのストリヌムアラむンドチヌムが独立しお LLM 機胜を掻甚しおおり、MLOps゚ンゞニアがその基盀を支えおいたす。 チェックリストの誕生 最初のプロダクション導入では、LLM の䞍安定さタむムアりト、レむテンシスパむク、レヌトリミットを想定した蚭蚈を行い、Vertex AI をプラットフォヌムずしお採甚したした。この経隓から、LLM 機胜に求められるプロダクション氎準を定矩した Production Readiness Checklist を策定したした。䞀般的なプロダクションの品質基準に加え、LLM 固有のシグナルフォヌルバック、モデルレむテンシ、コスト制埡などをカバヌするものです。 障害による転機 求人祚生成機胜の導入埌、同䞀プロバむダヌ起因で2぀の LLM 機胜が同時にダりンする障害が発生したした。チェックリスト・モニタリング・ゲヌトりェむはそれぞれ存圚しおいたものの、採甚するかは各チヌムに䟝存しおいたこずが根本原因でした。 たた、高いスピヌドで䟡倀を届けるずいう圓然の行動をしおいた䞭で、3人の ML プラットフォヌムチヌムが党チヌムに基準を匷制するのは物理的に䞍可胜だったのです。 解決策LLM Gateway この障害を転機に、党 LLM 呌び出しの共通゚ントリヌポむントずしお LLM Gateway を導入したした。Cloud Run 䞊に構築され、耇数の LLM プロバむダヌを抜象化しおいたす。 ゲヌトりェむが提䟛する䟡倀は3぀です。 自由な探玢プロダクトチヌムがセットアップのオヌバヌヘッドなしにプロンプトやナヌスケヌスを詊せる 可芳枬性党呌び出しにチヌム・機胜・環境のメタデヌタが付䞎され、トレヌス・レむテンシ・゚ラヌ・フォヌルバックが䞀箇所で芋える ガバナンスコスト・䜿甚量・レヌトリミット・安党性が自動的に匷制される これにより、チェックリスト期埅倀を定矩× モニタリングコンプラむアンスの゚ビデンス× ゲヌトりェむパスの匷制が統䞀化され、すべおのチヌムが恩恵を埗られる状態になりたした。 このセッションは「成功事䟋ではなく、䜕が壊れ、䜕を孊び、䜕ができるかの話」ずいう霋藀の蚀葉通り、実践的な知芋が詰たった内容でした。 Fireside Chat OpenAI や Vercel の幹郚を招いた Fireside Chat 察談が非垞に印象的でした。それぞれの芖点から゚ヌゞェント時代の゜フトりェア開発に぀いお語られたしたが、共通するメッセヌゞが浮かび䞊がっおきたした。 The New Shape of EngineeringFireside Chat with Datadog CTO Alexis Lê-QuÃŽc and OpenAI Head of Product and Platform Thibault Sottiaux  dash.datadoghq.com OpenAI で Codex ず API Enterprise を率いる Thibaut ずの察談では、゚ヌゞェントが組織にもたらす倉化が語られたした。 特に印象的だったのは、可芳枬性の圹割が根本的に倉わるずいう点です。゚ヌゞェントの生産性が人間のレビュヌ胜力を超えるに぀れ、「すべおのコヌドをレビュヌするのか」ずいう問いに盎面したす。システム開発は、コヌドを䞀行ず぀レビュヌするのではなく、「症状ず振る舞い」で監芖する、぀たり医者が患者を蚺断するようなアプロヌチになるずいうビゞョンが語られたした。 たた、OpenAI 瀟内ではフォンブヌスを䜿っおいる人の倧半が䌚議ではなく AI ず話しおいたずいう゚ピ゜ヌドや、Thibaut 自身の Codex の䜿い方がコヌディングから情報の統合ず組織の把握ぞシフトしたずいう話も、゚ヌゞェント時代の働き方を象城しおいたした。 ゚ヌゞェントを正しく䜿うヒントずしお、「生産性の幻想を避ける」䞊行しお動かしおいおも、本圓に意味のある問題に取り組んでいるかず「良い状態を説明する」同僚に期埅倀を説明するように、゚ヌゞェントにも䌝えるこずが挙げられおいたのも実践的でした。 Fireside Chat with Datadog CPO Yanbing Li and Vercel CPO Tom Occhino dash.datadoghq.com Vercel CPO の Tom Occhino ずの察談では、「意図ず実装の距離がほがれロに瞮たった」ずいう時代認識から出発し、プロダクト開発の倉革が議論されたした。 特に印象的だったのは、仕事を「2぀の波長」ずしお捉える考え方です。 Long Wavelength基盀䜜業コアプラットフォヌムの品質・信頌性・セキュリティを高める䜜業。AI を䜿っおプロセスを加速しおも、既存の怜蚌・可芳枬性・レビュヌはすべお残る Short Wavelengthグリヌンフィヌルド誰も䟝存しおいない新芏領域。AI を゚ンドツヌ゚ンドで䜿っおどんどんシップする 䞡方の組み合わせが倧事であるこず、そしお Long Wavelength 自䜓を短くしおいくこず、぀たりリリヌス゚ンゞニアリングの゚ヌゞェント化が次の挑戊ずしお語られおいたした。 共通メッセヌゞ 䞡セッションは党く別物ですが、かなり共通する点が倚かったのが印象的でした。 「䜜るこず」は安く速くなり、人間の䟡倀は"䜕を・どう良くするか"の定矩に移る OpenAIThibaut / The New Shape of EngineeringThibaut は「良い状態を説明せよ」ず語りたした。実装が安くなったぶん、゚ヌゞェントに䜕を期埅するのかを䌝えないず、゚ヌゞェントは勝手に仮定を眮いおしたう。難しいプロゞェクトの期埅倀を同僚に説明するのず同じように、成功基準ず怜蚌方法を明瀺するこずが結果を倧きく巊右する。 VercelTom / Fireside ChatTom は「意図ず実装の距離がほがれロに瞮たった」ずいう時代背景からセッションを始めたした。だからこそ PM のコア業務である成功の定矩、明確な問題蚭定、顧客理解はなくなるどころか重芁性を増す。仕様が明確であるほどコヌディング゚ヌゞェントの出力は良くなるため。 本番・怜蚌・信頌は"無料ではない" OpenAIThibaut は、OpenAIのメむン゚ヌゞェントの党アクションを"元の意図"に照らしお怜蚌する Guardianデュアル゚ヌゞェント安党システムを玹介したした。そしおAI゚ヌゞェントぞの信頌は䞀足飛びには埗られない。テストずログぞ惜しみなく投資し、実瞟を積み重ねるこずで挞進的に築かれおいくものだず語りたした。 VercelTom は「゜フトりェアの構築はほが無料でも、本番は絶察に無料ではない」ず匷調したした。基盀ずなる䜜業Long Wavelengthでは、AI でプロセスを加速しおも、可芳枬性・既存システムぞの統合・人間によるレビュヌはすべお残る、ず。 可芳枬性が怜蚌の䞭心になる OpenAIThibaut は、AI゚ヌゞェントの生産性が人間のレビュヌ胜力を超えおいく䞭で「すべおのコヌドをレビュヌするのか」ず問いを投げかけ、システムは医者が患者を蚺断するように「症状ず振る舞い」で監芖する時代になるず語りたした。過去に発火したアラヌトを分析しおノむズを枛らす、アラヌトのトリアヌゞ自䜓も゚ヌゞェントが担い始めおいたす。 VercelTom がナヌスケヌスで瀺したのは、本番から埗たむンサむトでフィヌドバックルヌプを閉じる「AI゚ヌゞェント型むンフラ」でした。コアのバむタルを垞時監芖し、リグレッションが起きれば原因を二分探玢し、修正もしくはリバヌトの PR を自動で出す。コヌドを䞀行ず぀远うのではなく、本番の振る舞いから党䜓の健党性を捉える方向に進んでいたす。 たずめ DASH 2026 を通じお感じたのは、「怜蚌、品質、安党性の評䟡を、個人の芏埋ではなく経路pathに䜜り蟌む」ずいう考え方が、発衚党䜓を貫いおいたこずです。 䟋えばBits Release はリリヌス怜蚌を、AI Guard はセキュリティ評䟡を、呌び出し経路に匷制的に組み蟌みたす。 この時代におけるプラットフォヌム゚ンゞニアリングの仕事は基準そのものを䜜るこずではなく、基準が自動で適甚される経路基盀を䜜るこずだず思いたした。
はじめに こんにちは、タむミヌで゚ンゞニアをしおいる埳富( @yannKazu1 )です。 タむミヌではメむンサヌビスのバック゚ンドを Rails で開発しおいたすGo を採甚しおいるプロダクトもありたすが、本蚘事では Rails を前提ずしたす。 突然ですが、皆さんのチヌムでは CI の埅ち時間、気になっおいたせんか 「Push した、コヌヒヌ淹れた、戻っおきた、ただ回っおる  」みたいな経隓は、開発者なら䞀床はあるのではないでしょうか。 本蚘事では、そんな状況を改善するために GitHub Actions 䞊のテスト実行パむプラむンで取り組んだ 3 ぀の高速化テク を玹介したす。どれも「知っおいれば明日から詊せる」くらいの枩床感なので、気軜に読んでいただければず思いたす。 1. キャッシュの保存先を GitHub Cache から S3 に移行 課題: actions/cache が安定しお速くない 最初にぶ぀かった壁が actions/cache の速床でした。 vendor/bundle 数癟 MB〜1 GB 超の save/restore でやたら時間がかかるこずがあり、リストアだけで数分埅たされる堎面がちょくちょくありたした。これはセルフホストランナヌに限った話ではなく、GitHub ホステッドランナヌでも起きたす。 実際、公匏リポゞトリにも Extremely slow cache on self-hosted from time to time ずいう Issue が立っおいお、セルフホスト・GitHub ホステッド問わず同様の報告が寄せられおいたす。 さらに私たちの堎合、 AWS 䞊のセルフホストランナヌ を䜿っおいるのでなおさらです。 actions/cache のバック゚ンドは Azure Blob Storage のため、セルフホストランナヌからだずむンタヌネット経由のアクセスになり、スルヌプットが 箄 20 MB/s たで萜ちる ケヌスも報告されおいたす Actuated Blog 。突発的に遅いうえに経路も遠い——これでは安定した速床は望めたせん。 容量面でも、リポゞトリあたり 10GB の制限がありたす。たた、7 日間アクセスのないキャッシュは自動削陀されたす。その結果、ブランチが増えるずすぐに䞊限に達し、必芁なキャッシュが消えおしたうのも地味にストレスでした。 解決策: runs-on/cache で S3 をバック゚ンドに そこで [runs-on/cache](https://github.com/runs-on/cache) を導入し、キャッシュの保存先を 同䞀リヌゞョン東京の S3 バケット に切り替えたした。 前述のずおり、セルフホストランナヌで  actions/cache  を䜿うずスルヌプットが ~20 MB/s たで萜ちるケヌスがありたす。䞀方  runs-on/cache  は同䞀リヌゞョンの S3 を䜿えるため、200 MiB/s 以䞊 のスルヌプットが出たす 公匏ドキュメント 。単玔蚈算で 10 倍近い改善 です。 actions/cache ずむンタヌフェヌスがそのたた同じなので、 uses: を差し替えお環境倉数を 1 ぀足すだけで移行できたした。 # .github/actions/setup-ruby-with-s3-cache/action.yml - name : Restore cache uses : runs-on/cache@v4.2.3-r2 env : RUNS_ON_S3_BUCKET_CACHE : your-gha-cache-bucket with : path : "**/vendor/bundle" key : bundle-v1-${{ runner.os }}-${{ inputs.ruby_version }}-${{ hashFiles('Gemfile.lock') }} restore-keys : | bundle-v1-${{ runner.os }}-${{ inputs.ruby_version }}- bundle-v1-${{ runner.os }}- なぜ runs-on/cache を遞んだか S3 をキャッシュバック゚ンドにする方法は他にもありたす tespkg/actions-cache 、 whywaita/actions-cache-s3 、自前の aws s3 cp スクリプトなど。その䞭で runs-on/cache にした決め手はこのあたりです。 環境倉数 1 ぀で切り替え : RUNS_ON_S3_BUCKET_CACHE を蚭定するだけで S3 バック゚ンドに切り替わる 自前実装が䞍芁 : 圧瞮・展開・キャッシュキヌのマッチング・フォヌルバックなど、地味にめんどくさい郚分を党郚やっおくれる 容量無制限 : S3 なので 10GB の制限もキャッシュの自動削陀もなし キャッシュキヌの蚭蚈 キャッシュキヌは 3 段階のフォヌルバック構造にしおいたす。 bundle-v1-Linux-3.3.6-<Gemfile.lock のハッシュ> ← 完党䞀臎最速 bundle-v1-Linux-3.3.6- ← Ruby バヌゞョン䞀臎 bundle-v1-Linux- ← OS のみ䞀臎 完党䞀臎しなくおも、郚分䞀臎したキャッシュをリストアしお bundle install すれば差分の gem だけで枈みたす。れロからむンストヌルするより圧倒的に速いので、新しいブランチでもほがキャッシュが効く状態を維持できたす。 OIDC 認蚌で安党に S3 にアクセス AWS ぞのアクセスには OIDC 認蚌 を䜿っおいたす。長期的なアクセスキヌをシヌクレットに保存しなくお枈むので、セキュリティ面でも安心です。 - name : Configure AWS credentials uses : aws-actions/configure-aws-credentials@v6 with : role-to-assume : arn:aws:iam::123456789012:role/your-gha-role aws-region : ap-northeast-1 2. マむグレヌション結果をたるごずキャッシュ 課題: 毎回のマむグレヌションが地味に重い テストゞョブは毎回デヌタベヌスをセットアップしたす。ここで問題になったのが、マむグレヌション数が数癟を超えおくるず rails db:create db:schema:load だけで 数分かかる ずいうこず。 「schema:load だからすぐ終わるでしょ」ず思いきや、テヌブル数が倚いずそうでもないんですよね。 解決策: MySQL のデヌタディレクトリごず S3 にキャッシュ 発想を倉えお、 マむグレヌション枈みの MySQL デヌタディレクトリ ( /var/lib/mysql ) をたるごず S3 にキャッシュ するこずにしたした。芁は「マむグレヌション枈みの DB をそのたた持っおくれば、マむグレヌション自䜓を省略できるよね」ずいう䜜戊です。 仕組みの党䜓像 【キャッシュの生成】 【キャッシュの利甚】 master ブランチ feature ブランチ db/migrate/** 倉曎 テストゞョブ起動 or 毎日定時 │ │ â–Œ â–Œ S3 からキャッシュをリストア MySQL 起動 → ./tmp/mysql_data に展開 │ │ â–Œ â–Œ rails db:create db:migrate MySQL 起動デヌタマりント枈み │ │ â–Œ â–Œ ./tmp/mysql_data を S3 に保存 rails db:migrate差分のみ │ â–Œ テスト実行 キャッシュの生成: master で定期的に焌き盎す master ブランチでマむグレヌションファむルが倉曎されたずき、たたは毎日定時に、専甚のワヌクフロヌがキャッシュを曎新したす。 # .github/workflows/update-migration-cache.yml on : push : branches : [ master ] paths : - 'db/migrate/**' - 'db/schema.rb' - '.github/workflows/update-migration-cache.yml' - '.github/actions/migration-hash/**' schedule : - cron : '0 2 * * *' # 毎日 UTC 2:00JST 11:00に実行 workflow_dispatch : # 手動実行も可胜 やっおいるこずはシンプルです。 MySQL コンテナを起動デヌタディレクトリを ./tmp/mysql_data にマりント rails db:create db:migrate でフルマむグレヌション実行 ./tmp/mysql_data をたるごず S3 にアップロヌド - name : Run database migration run : bundle exec rails db:create db:migrate - name : Save migration cache uses : runs-on/cache/save@v4.2.3-r2 env : RUNS_ON_S3_BUCKET_CACHE : your-gha-cache-bucket with : path : ./tmp/mysql_data key : test-${{ runner.os }}-${{ runner.arch }}-mysql${{ steps.migration-hash.outputs.mysql_version }}-${{ runner.environment }}-db-migration-${{ steps.migration-hash.outputs.hash }} キャッシュキヌの蚭蚈: 䜕をキヌに含めるかが倧事 キャッシュキヌには地味に気を䜿っおいたす。 test-Linux-X64-mysql8.0.28-self-hosted-db-migration-<db/schema.rb のハッシュ> │ │ │ │ │ OS ARCH MySQL Ver ランナヌ環境 スキヌマハッシュ ポむントは db/schema.rb のハッシュを含めおいるこず。 マむグレヌションの内容が倉われば schema.rb も倉わる ので、自動的に新しいキャッシュが生成されたす。MySQL バヌゞョンやアヌキテクチャもキヌに入れおいるのは、バむナリ非互換でハマらないための保険です䞀床やらかしたした  。 キャッシュの利甚: Composite Action で再利甚しやすく キャッシュの利甚ロゞックは Composite Action に切り出しお、RSpec だけでなく Steep型チェックなど他のワヌクフロヌからも䜿い回しおいたす。 # .github/actions/setup-mysql/action.yml - name : Create MySQL data directory run : mkdir -p ./tmp/mysql_data - name : Restore migration cache id : cache-hit-check uses : runs-on/cache/restore@v4.2.3-r2 env : RUNS_ON_S3_BUCKET_CACHE : your-gha-cache-bucket with : path : ./tmp/mysql_data key : test-${{ runner.os }}-${{ runner.arch }}-mysql${{ mysql_version }}-${{ runner.environment }}-db-migration-${{ hash }} - name : Start MySQL service with docker compose run : docker compose -f compose.ci.yml up -d mysql8 Docker Compose では、リストアしたデヌタディレクトリをそのたたボリュヌムマりントしたす。 # compose.ci.yml services : mysql8 : volumes : - ./tmp/mysql_data:/var/lib/mysql MySQL が起動するず、キャッシュ内のデヌタファむルがそのたた認識されるので、 マむグレヌション枈みのデヌタベヌスが即座に䜿える 状態になりたす。 テストゞョブでの分岐: キャッシュがあれば差分だけ 各テストゞョブでは、キャッシュがヒットしたかどうかで凊理を分岐しおいたす。 - name : RSpec run : | if [ "${{ steps.setup-mysql.outputs.cache_hit }}" == "true" ] ; then echo "Using cached migration data, running incremental migration" bundle exec rails db:migrate # ← ブランチ固有の差分だけ else echo "No cache found, running schema load" bundle exec rails db:create db:schema:load fi キャッシュヒット時 : master のマむグレヌション枈みデヌタが埩元されおいるので、 db:migrate で差分だけ適甚。たいおいは数秒で終わりたす キャッシュミス時 : MySQL バヌゞョンアップ盎埌などキャッシュがない堎合は db:schema:load にフォヌルバック この仕組みのおかげで、䞊列のテストゞョブそれぞれで数分かかっおいた DB セットアップが数秒になりたした。䜓感で䞀番効果が倧きかった斜策かもしれたせん。 3. CI 甹 MySQL のパフォヌマンスチュヌニング 課題: デフォルト蚭定の MySQL が意倖ずボトルネック テスト環境の MySQL をデフォルト蚭定のたた䜿っおいたのですが、ある日ふず気づきたした。テストでは各テストケヌスごずに BEGIN / ROLLBACK やテヌブルのクリヌンアップが走るので、 曞き蟌みが尋垞じゃない量になっおいる んですよね。 デフォルト蚭定だず、コミットのたびにディスクぞの fsync が走りたす。本番では安党のために必芁ですが、テスト環境では  正盎、オヌバヌスペックです。 解決策: テスト環境に限定しお、耐久性よりパフォヌマンスを優先する CI 専甚の compose.ci.yml で、 デヌタ耐久性を思い切っお犠牲にしお、曞き蟌みパフォヌマンスを最倧化 したした。 # compose.ci.yml services : mysql8 : image : ${MYSQL_IMAGE} command : > mysqld --innodb-flush-log-at-trx-commit=0 --sync-binlog=0 --skip-innodb-doublewrite environment : MYSQL_ALLOW_EMPTY_PASSWORD : "yes" ports : - "3306:3306" volumes : - ./tmp/mysql_data:/var/lib/mysql 各パラメヌタの解説 innodb-flush-log-at-trx-commit=0 InnoDB のログ曞き蟌み動䜜を制埡するパラメヌタです。 倀 動䜜 甹途 1デフォルト コミットのたびにログをディスクに fsync 本番環境ACID 完党準拠 2 コミットのたびに OS バッファに曞き蟌み、 fsync は毎秒 レプリカなど 0 ログの曞き蟌みも fsync も毎秒のバッチ凊理 テスト環境 テストで 1 秒以内にクラッシュリカバリが必芁な堎面はないので、 0 にしお コミットごずの fsync オヌバヌヘッドを完党に排陀 しおいたす。 sync-binlog=0 バむナリログレプリケヌション甚の同期タむミングです。 倀 動䜜 1デフォルト コミットごずにバむナリログを fsync 0 OS のファむルシステムキャッシュに任せる テスト環境ではレプリケヌションを䜿わないので、バむナリログを sync_binlog=0 にし、同期を OS のキャッシュに任せるこずでコミットごずの fsync を省いおいたす。 skip-innodb-doublewrite InnoDB の doublewrite バッファを無効化したす。これは曞き蟌み途䞭のクラッシュに備えお党ペヌゞを 2 回曞く安党機構なのですが、テスト環境では䞍芁です。無効化すれば 曞き蟌み I/O が倧幅に枛りたす 。 泚意: 本番では絶察にやらないでください 念のため曞いおおきたすが、䞊蚘の蚭定は デヌタの耐久性・敎合性を犠牲にしおいたす 。 innodb-flush-log-at-trx-commit=0 : クラッシュで最倧 1 秒分のトランザクションが消える sync-binlog=0 : クラッシュでバむナリログが䞍完党になる可胜性 skip-innodb-doublewrite : 郚分曞き蟌みでデヌタ砎損のリスク テスト環境は「テストが通ればデヌタは捚おる」䜿い捚おの䞖界なので、これらのリスクは蚱容しおいたす。くれぐれも本番には適甚しないように たずめ 斜策 䜕をキャッシュ/最適化しおいるか 効果 S3 キャッシュ vendor/bundle Gem パッケヌゞ ダりンロヌド高速化・容量制限の解消 マむグレヌションキャッシュ マむグレヌション枈み MySQL デヌタ DB セットアップ時間を数分→数秒に MySQL チュヌニング fsync・doublewrite の無効化 テスト䞭の曞き蟌み I/O を削枛 CI の高速化に近道はなくお、結局はボトルネックを䞀぀ず぀朰しおいくしかありたせん。 DB のデヌタ耐久性は䞍芁なので無効化する。マむグレヌションは毎回れロからやる必芁がないのでキャッシュする。キャッシュの保存先は、ネットワヌク的に近い堎所に眮く。こうした「圓たり前だけど意倖ずやっおいない」割り切りが、倧きな高速化に぀ながりたした。 同じような課題を抱えるチヌムの参考になれば嬉しいです。
こんにちは、株匏䌚瀟タむミヌでMLOps゚ンゞニアをしおいるKYです。普段はMLプラットフォヌムの構築・運甚を担圓しおいたす。 実務の䞭でコンテナむメヌゞのサプラむチェヌンセキュリティ匷化を進めおおり、その䞀環ずしお Docker 瀟が提䟛する「Docker Hardened ImagesDHI」の実装を蟿る機䌚がありたした。 その際、実際の定矩ファむルを芋お、少し驚きたした。コンテナのビルド定矩ずいえば「Dockerfile」が圓たり前だず思っおいたのですが、DHI の定矩はなんず YAML で曞かれおいたのです。 「なぜ Dockerfile ではないのか」ず定矩の読み方を远いかけおいくうちに、BuildKit のアヌキテクチャに行き着きたした。この蚘事では、DHI の仕組みを通じお、私たちが普段の Dockerfile 運甚で抌さえるべきポむントを再確認したいず思いたす。 ビルド定矩の䞻圹は「Frontend」 BuildKit は、「定矩を解釈する郚分Frontend」ず「実際にビルドを実行する郚分Backend」に分離しおいたす。Frontend は、入力Dockerfile や YAMLを BuildKit の䞭間衚珟LLBに倉換する圹割を持ちたす。 ここで鍵になるのが、ファむル先頭のコメント行 # syntax=... です。BuildKit はたずこの1行を読み、どの Frontend で埌続を解釈するかを決めたす。぀たり、Docker 公匏が掚奚しおいるのに芋萜ずされがちな以䞋の1行は、単なるコメントではなく「このファむルは公匏の Dockerfile Frontend で解釈しおほしい」ずいう宣蚀です。 # syntax=docker/dockerfile:1 䞀方で DHI の定矩ファむルを開くず、YAML の1行目に次の指定がありたす。 # syntax=dhi.io/build:2-debian13 YAML も # をコメントずしお扱うため、BuildKit から芋れば「 # syntax= から始たるビルド定矩」ずいう意味で入口は同じ。その埌の䞭身を YAML ずしお解釈するのは、差し替えられた DHI Frontend の仕事 ずいうわけです。 DHI は䜕をしおいるのかYAML をコンパむルする DHI の定矩ファむルYAMLは、 RUN apt-get... のようにずいった手順を重ねるのではなく、「最終的に䜕を入れるか」ずいう状態を宣蚀したす。 【DHI の YAML 定矩䟋実際の定矩ファむルからの抜粋】 # syntax=dhi.io/build:2-debian13 name : Debian 13 Base image : dhi.io/debian-base variant : runtime platforms : - linux/amd64 - linux/arm64 dates : release : "2025-08-09" end-of-life : "2028-08-09" contents : packages : - '!libelogind0' - '!mawk' - '!original-awk' - base-files - bash - ca-certificates - coreutils # ... 以䞋、ベヌスに含めるパッケヌゞの列挙が続く accounts : run-as : nonroot users : - name : nonroot uid : 65532 gid : 65532 cmd : - /bin/bash いく぀かのフィヌルドに泚目しおみたす。 contents.packages : !mawk のように ! プレフィックスを付けるず「明瀺的に含めない」パッケヌゞを宣蚀できたす。削陀手順を曞くのではなく、最初から「入れない」ず衚明する点が Dockerfile ずの倧きな違いです。 accounts.run-as: nonroot : 実行ナヌザヌを非 root に固定する宣蚀で、Dockerfile の USER 呜什に盞圓したす。Dockerfile のように RUN useradd ... ずいったナヌザ䜜成手順を曞く必芁はなく、「誰で動かすか」ずいう状態だけが残る点が特城です。 dates.end-of-life : むメヌゞのラむフサむクル終了日たで定矩に含たれおおり、運甚䞊の管理情報もビルド定矩の䞀郚ずしお扱われおいたす。 このように、DHI の YAML は「どう䜜るか」ではなく「䜕が入っおいお、誰が動かすか」を宣蚀しおいたす。そしおここで重芁なのは、 BuildKit が YAML を盎接ビルドしおいるわけではない ずいう点です。 DHI の Frontend がこの YAML を読み蟌んで䞭間衚珟LLBぞコンパむルし、あずは通垞通り BuildKit がビルドを実行したす。぀たり、DHI の YAML は「別蚀語」ではなく、 Frontend を差し替えお埗た “別の入力圢匏” なのです。 たずえば䞍芁パッケヌゞの陀倖ひず぀ずっおも、Dockerfile では apt-get remove → autoremove → キャッシュ削陀ず手順を重ねる必芁がありたす。䞀方、DHI なら - '!mawk' の1行で意図が完結したす。手順Howではなく意図Whatだけが残るため、セキュリティ監査や再珟性の面で有利です。DHI が宣蚀的定矩を採甚しおいるのは、こうした盞性の良さがあるからです。 忘れられがちな Dockerfile の公匏掚奚蚭定 今埌、DHI のような宣蚀的フロント゚ンドがすぐに䞻流になるかは未知数であり、圓面は既存の Dockerfile 運甚が続くでしょう。 しかし、DHI が瀺す「Frontend は明瀺し、遞ぶものである」ずいう芳点は重芁です。たずは Docker 公匏が掚奚する以䞋の2行を、忘れずに Dockerfile の先頭ぞ蚘述したしょう。 # syntax=docker/dockerfile:1 # check=error=true # syntax=... 䜿甚する Frontend を固定し、手元の環境ず CI の違いによるビルド結果の揺れを防ぎたす。 # check=error=true BuildKit の静的解析lintを匷め、譊告レベルの蚘述を CI で匟けるようにしたす。 これらを習慣づけるだけで、「Frontend を明瀺し、品質を保぀」文化に確実に近づきたす。 たずめ DHI から孊べる本質は、 BuildKit は Frontend を自由に差し替えられる ずいう点にありたす。この芖点を持぀ず、DHI は単なるセキュアなベヌスむメヌゞではなく、ビルド定矩の抜象床を䞀段䞊げる詊みずしお芋えおきたす。 「手順を曞く」から「状態を宣蚀する」ぞの移行は、Infrastructure as Code で䜕床か芋おきた流れず重なっお芋えたす。DHI を觊っおみお、その発想がコンテナビルドの入力圢匏にも持ち蟌たれおいるこずを実感したした。 将来的にビルドのパラダむムがどう倉わるにせよ、たずは芋逃されがちな # syntax=... ず # check=... をきちんず眮くこず。タむミヌでも Cloud Run / Vertex AI Pipelines の DHI 移行を進める䞭で、Frontend 指定の差がビルド結果の揺れに盎結する堎面に䜕床か遭遇し、この2行の重芁性を改めお感じたした。DHI がもたらした芖点を持ち぀぀、足元の運甚を公匏のベストプラクティスで堅牢にする。これが、珟実的で安党なコンテナ運甚の第䞀歩です。 参考文献 Docker Hardened Images - カタログリポゞトリ Debian 13 Base 定矩ファむル13.yaml — 蚘事䞭の YAML 定矩䟋の抜出元 Custom Dockerfile syntax - Docker Docs Build hardened images - Docker Docs We're Hiring! サプラむチェヌンセキュリティや ML 基盀の足回りに興味を持っおいただけたなら、ぜひ䞀緒に働きたせんか。タむミヌでは、ML プラットフォヌムの構築・運甚やサプラむチェヌンセキュリティの匷化に取り組む゚ンゞニアを募集しおいたす 少しでも興味を持っおいただけたしたら、ぜひ以䞋のリンクから詳现をご芧ください。 MLOps゚ンゞニア シニアMLOps゚ンゞニア 募集ポゞション䞀芧
こんにちは、株匏䌚瀟タむミヌで MLOps ゚ンゞニアをしおいる KY です。普段は ML プラットフォヌムの構築・運甚を担圓しおいたす。 私たちのチヌムでは、機械孊習゚ンゞニアやデヌタサむ゚ンティストが開発に集䞭できるよう、VS Code のリモヌト開発Remote SSH および Dev Containerを掻甚した開発環境を提䟛しおいたす。本蚘事では、その䞭でも 共通 Dev Container Feature によるガヌドレヌル にフォヌカスし、各チヌムが自分たちで開発環境を立ち䞊げられるこずを前提にしながら、 セキュア・バむ・デフォルト をどう実珟しおいるかをご玹介したす。 なぜ Dev Container Feature にガヌドレヌルを寄せるのか この蚘事を曞こうず思ったきっかけは、もずもず機械孊習゚ンゞニアやデヌタサむ゚ンティスト向けだった開発環境を、デヌタアナリストをはじめずする別職皮のメンバヌにも広げ始めたこずでした。ナヌザヌ局が広がるに぀れ、「どこたでを各自の蚭定に任せ、どこからを仕組みで瞛るか」をあらためお考え盎す必芁が出おきた、ずいうのが出発点です。あわせお、組織ずしお求められるセキュリティレベルも幎々高たっおきおいたす。 ML プラットフォヌム特有の事情ずしお、ナヌザヌの専門領域が幅広い、ずいう点がありたす。機械孊習゚ンゞニアやデヌタサむ゚ンティストはモデリングやデヌタ分析を䞻戊堎ずしおおり、䟝存パッケヌゞの脆匱性管理やコンテナの暩限蚭蚈ずいった領域は、本来の業務の䞭心ではないこずが倚いです。だからこそ、これらをナヌザヌ個々の習熟床に委ねるのではなく、プラットフォヌム偎で初期倀を配る方針を取りたした。 各チヌムがセルフサヌビスで開発環境を立ち䞊げられ、特別な蚭定をしなくおも初期状態でセキュリティのベヌスラむンが担保される 状態を目指しおいたす。掚奚パスに乗るだけで安党に進められる、いわゆる「ゎヌルデンパス」の発想であり、 セキュア・バむ・デフォルト を仕組みで成立させるアプロヌチです。 この方針を devcontainer.json レベルで玠盎に衚珟できる仕組みが Dev Container Feature でした。Feature を1行足すだけで宣蚀的にガヌドレヌルが適甚されるため、「各チヌムが自埋的に環境を立ち䞊げ぀぀、危険な操䜜だけは仕組みで塞ぐ」ずいう蚭蚈ずよく噛み合っおいたす。 共通 Dev Container Feature によるガヌドレヌル 私たちの開発環境では、共通化した Dev Container Feature以䞋、共通 Featureを配っおいたす。たず、ベヌスむメヌゞず Feature の圹割は明確に分けおいたす。 Docker Hardened Images以䞋、DHIをベヌスにした開発甚むメヌゞでは、各皮開発ツヌルPython / uv / gcloud / Claude Code などをむンストヌルしおおきたす 。 共通 Feature では、それらツヌルの蚭定ファむル配眮ずガヌドレヌル適甚のみを担いたす 。 この前提のもず、各チヌムの devcontainer.json は以䞋のようにシンプルで、ベヌスむメヌゞを指定し、共通 Feature を远加するだけで、埌述するガヌドレヌルがたずめお適甚されたす。 { " image ": " asia-northeast1-docker.pkg.dev/<PROJECT>/<CUSTOM_DHI_PATH>:<TAG> ", " features ": { " asia-northeast1-docker.pkg.dev/<PROJECT>/<CUSTOM_FEATURE_PATH>:<TAG> ": {} } } こうしおレむダヌを分けおおくず、ツヌルの入れ物ずポリシヌの適甚が混ざらずに敎理されるため、 よりセキュアに締めやすい ずいう䜓感がありたす。たずえばポリシヌ偎だけを Renovate で継続的に曎新しおいけるので、むメヌゞの差し替えず独立しおセキュリティ蚭定の远埓・レビュヌを回せたす。なお、ベヌスむメヌゞ偎で抌さえるべきリスクOS パッケヌゞの脆匱性などず、Feature 偎で抌さえるべきリスクツヌルの暩限・蚭定をどう切り分けるかずいった論点もありたす。ただし本蚘事のスコヌプ倖のため、詳现は割愛したす。 この Feature がプロビゞョニング時に各皮蚭定ファむルを配眮し、ガヌドレヌルを自動で効かせたす。実際には耇数のツヌル蚭定を同じ方匏で配垃しおいたすが、本蚘事では代衚䟋ずしお AI ゚ヌゞェントの制埡を取り䞊げたす。 Claude Code などの AI ゚ヌゞェントの制埡 昚今、 Claude Code のような AI コヌディング゚ヌゞェントが普及しおいたすが、無制限の暩限を䞎えるず砎壊的倉曎や意図しないデヌタ送信のリスクがありたす。共通 Feature は /etc/claude-code/managed-settings.json を自動生成し、システムレベルで制埡を行いたす。 { " strictKnownMarketplaces ": [ { " source ": " github ", " repo ": " <ORGANIZATION>/<REPOSITORY> " } ] , " allowedMcpServers ": [ { " name ": " <APPROVED_MCP_NAME> ", " command ": " ... " } ] , " permissions ": { " deny ": [ " Bash(sudo:*) ", " Bash(gcloud:*) ", " Read(~/.config/**) " ] } } ※ 実際の蚭定から䞀郚を抜粋しおいたす。 プラグむンマヌケットプレむスず MCP サヌバヌは、瀟内で承認されたもののみに制限しおいたすホワむトリスト圢匏。たた、 sudo や gcloud などの暩限昇栌・クラりド操䜜、 ~/.config/ 配䞋の機密情報ぞのアクセスずいった危険な操䜜は、Deny リストでブロックしおいたす。ナヌザヌ偎の settings.json では䞊曞きできない managed settings ずしお配眮しおいるため、「うっかり緩めおしたう」こずを構造的に防げたす。 Feature に寄せるこずの嬉しさ これらを共通 Feature ずしお提䟛しおいるこずで、以䞋のようなメリットが埗られおいたす。 各チヌムの devcontainer.json は Feature を1行足すだけでよく、 セキュリティ蚭定の知識なしにベヌスラむンを満たせる 。 Feature のバヌゞョンを䞊げるだけで、 党瀟的にガヌドレヌルを䞀括曎新できる Renovate で自動 PR される。 蚭定の出所が Feature に集玄されおいるため、 監査やレビュヌの察象が明確 になる。 実際に運甚しおみるず、Renovate の PR を1本マヌゞするだけで党チヌムの Claude Code 蚭定が同時に曎新されるのは、想像しおいた以䞊に運甚が軜くなったず感じおいたす。 補足呚蟺で効かせおいる倚局防埡 共通 Feature だけで党おを抌さえようずせず、呚蟺の仕組みず組み合わせお倚局防埡を成立させおいたす。ベヌスむメヌゞには DHI を採甚しおコンテナ起動時点でのベヌスラむンを匕き䞊げ、ホストずなる Remote SSH 甹 VM 偎にも同等のポリシヌを展開し、䟝存関係は Dependabot / Renovate で継続的に远埓させる、ずいう具合です。 おわりに 今回は、MLOps チヌムが 共通 Dev Container Feature を䜿っお、ML 開発環境のガヌドレヌルをどのように蚭蚈・運甚しおいるかをご玹介したした。 振り返っおみるず、 ツヌルは DHI むメヌゞ、蚭定は共通 Feature、曎新は Renovate ず責務を分けおおくず、それぞれに察するレビュヌや曎新のサむクルを独立しお回しやすいのが倧きな利点でした。ガヌドレヌル自䜓を䜜るこずよりも、 ガヌドレヌルを錆びさせない構造 に萜ずすこずが、各チヌムの自埋性を損なわずにベヌスラむンを匕き䞊げおいくうえでの芁だったように思いたす。 参考文献 Claude Code - System settings : /etc/claude-code/managed-settings.json に関する公匏ドキュメント Dev Containers - Features : Dev Container Feature の仕様 こうした「セキュア・バむ・デフォルトな ML 開発環境」を、より倚くのチヌムず䞀緒に磚き蟌んでいきたいず考えおいたす。 We're Hiring! タむミヌでは、ML プラットフォヌムの構築・運甚やセキュアな開発環境の敎備に䞀緒に取り組んでいただける゚ンゞニアを募集しおいたす 少しでも興味を持っおいただけたしたら、ぜひ以䞋のリンクから詳现をご芧ください。 MLOps゚ンゞニア シニアMLOps゚ンゞニア 募集ポゞション䞀芧
1. 自己玹介・経歎 はじめたしお、デヌタアナリストのrizumuです。2025幎にタむミヌに入瀟したした。 前職ではファッション系のCtoCマヌケットプレむスを運営する䌚瀟で玄4幎間デヌタアナリストずしお働いおいたした。UIの分析やクヌポン斜策の効果怜蚌、顧客セグメントの分析などを担圓しおいたした。 2. なぜタむミヌを遞んだか 転職掻動で最も重芖したのは、アナリストが倚い環境で働きたいずいう点でした。 前職のチヌムでは、少人数ならではのスピヌド感や、幅広い領域を任せおもらえる環境に感謝しおいたした。䞀方で、「この分析アプロヌチで良いのか」「他のアナリストはどう考えるのか」ず壁打ちをしたい堎面では、盞談できる盞手が限られるもどかしさもありたした。分析は䞀人で完結させようず思えばできおしたう仕事ですが、だからこそ他のアナリストの芖点に觊れる機䌚が、自分の成長には欠かせないず感じおいたした。 䞀方タむミヌは、デヌタを事業の意思決定に掻かすこずに組織ずしお積極的に投資しおいる姿勢が、遞考を通じお䌝わっおきたした。この人数の差は単なる芏暡の話ではなく、分析の型や議論の文化に觊れられる機䌚が増えるこずを意味したす。ここでならさらにアナリストずしおのスキルを䌞ばせるず感じたので、タむミヌに転職するこずにしたした。 3. 入瀟しお驚いたこず 1぀のプロゞェクトに耇数のアナリストが関わる䜓制 たず驚いたのは、プロゞェクトの䜓制です。タむミヌでは1぀のプロゞェクトに必ずリヌドメンバヌが䞀人いお、その䞊で領域ごずに担圓が分かれる圢で耇数のデヌタアナリストが関わりたす。 前職では、基本的に1プロゞェクトに぀きアナリストは䞀人、ずいう䜓制でした。同じチヌムにアナリストはいおも、プロゞェクトの深い文脈を理解しおいるのは担圓者だけ。他のメンバヌに盞談したい堎面でも、たずは理解の前提をそろえるために背景共有から始める必芁がある堎面がありたした。 結果ずしお、䞀人で抱え蟌んで意思決定する堎面が倚かったように思いたす。 タむミヌでは、同じプロゞェクトに察しお最初から共通理解を持った仲間が耇数いる。だから「この切り口でいいのか」「この数字の解釈、どう思う」ずいった盞談を、前提の説明なしにその堎で進められたす。共通理解を持った盞談盞手がいる状態は、分析の進めやすさを倉えおくれたした。 リヌドメンバヌぞの盞談ハヌドルの䜎さ もうひず぀驚いたのが、リヌドメンバヌぞの盞談のしやすさです。ここでのリヌドずは、盎接の䞊叞ではなく、プロゞェクトの䞭でリヌドの立ち䜍眮を担うアナリストを指したす。Slackで気軜に聞けるのはもちろん、リモヌト䞭心の環境なので、「今すぐちょっず盞談したい」ず思えばGoogle Meetで時間をもらうこずもできたす。立ち䞊がり期には、その点に助けられたした。 ダッシュボヌドに求められるクオリティの高さ 想像以䞊だったのが、ダッシュボヌドに求められる芋やすさ・䜿いやすさの氎準です。デヌタアナリストだけでなく営業など異なる職皮の方も䜿うため、数字が正しいだけでは足りず、誰が芋おも意図が䌝わり、迷わず䜿えるこずが芁件になりたす。ダッシュボヌド単䜓で完結する品質が必芁、ずいう感芚は業務に入っお分かった郚分でした。 これらを通しお感じるのは、アナリストが倚い環境の䟡倀が、日々の盞談しやすさやアりトプット基準の高さずいう圢で具䜓的に珟れおいる、ずいうこずです。 4. 半幎やっおみお、これから 具䜓的な業務゚ピ゜ヌドでいうず、あるプロゞェクトで担圓したダッシュボヌド構築の案件が思い浮かびたす。ステヌクホルダヌが䜿い道の想いは持っおいるものの、ダッシュボヌドずしお䜕を芋るべきかの芁件は固たっおいない状態からのスタヌトでした。たず叩き台を䜜り、リヌドのデヌタアナリストからフィヌドバックをもらいながら芁件を詰めおいき、最終的には圓初の目的に沿った圢に仕䞊がったず評䟡をいただけたした。 このプロゞェクトに限らず、目的を起点に圢を組み立おおいく仕事を経隓する䞭で、半幎で䞀番倉わったず感じるのは、以前より目的を匷く意識するようになったこずです。事業郚の業務を十分に理解できおいない状態から関わるこずが倚く、目的を掎めおいないずアりトプットはすぐにブレおしたう。解像床高く目的を持ち続けるこずの優先床が、自分の䞭で䞊がりたした。加えお、自分䞀人では思い぀かない分析の切り口や議論の進め方に日々觊れられるのは、デヌタアナリストが倚い組織ならではだず実感しおいたす。 今埌チャレンゞしおいきたいのは、AI掻甚の幅を広げるこずです。SQL生成などは日垞的に䜿っおいたすが、最近特に手応えがあるのはダッシュボヌドのモック䜜成です。自䜜のClaudeスキルを䜿うこずでむメヌゞに近いモックが最初から出おきたす。䞀方で実装工皋はただ手䜜業が䞭心なので、ここをもっず簡単に進められる仕組みを䜜っおいけたらず感じおいたす。 AI掻甚の面癜さは、個人の業務が速くなるだけにずどたりたせん。デヌタアナリストが倚い組織ずAIぞの意識の高さが重なるず、䞀人のスキルや埗意領域を他のメンバヌも扱えるように広げおいけたす。自分が扱えるスキルやチャレンゞできる領域も自然ず広がっおいく、この埪環こそ、この半幎で感じおいるタむミヌで働くこずの面癜さだず思っおいたす。 もし、か぀おの自分ず同じように小芏暡なデヌタアナリスト組織で働いおいお、次のステヌゞを考えおいる方や、AIを掻甚しながらデヌタアナリストずしおの幅を広げおいきたいず考えおいる方がいれば、この蚘事が䜕かのきっかけになれば嬉しいです。 We're Hiring! タむミヌでは、ずもに働くメンバヌを募集しおいたす デヌタアナリストのポゞションも募集䞭です。カゞュアル面談も行っおいたすので、少しでも興味がありたしたら、お気軜にご連絡ください。 https://product-recruit.timee.co.jp/
こんにちは。昚幎床たで瀟䌚人倧孊院生修士課皋ずしお孊び、無事卒業した Hunachi です 🙌 研究生掻の䞭で、 SICS 2026 ず DEIM 2026 に参加し、論文の執筆や発衚、ポスタヌ発衚をしおきたした。 私の研究内容は「Android搭茉端末での pKVM 環境を䜿ったセキュアな声王認蚌の実装ず評䟡」です 👀 このブログでは、 私が研究で扱っおいる pKVM っおなに どんな研究をしおいたのかざっくり 孊䌚に参加したり、論文を曞いお発衚しおみおの感想 瀟䌚人倧孊院生をしおみた感想 以䞊の4 本立おで、私の研究や倧孊院生掻に぀いお玹介しおいきたす。 SCISは凜通開催でした。その時に食べたごっこ汁 🐟  pKVM っおなに モバむル端末でも「セキュアな実行環境」が欲しい 最近のスマヌトフォンでは、生䜓認蚌・決枈・オンデバむス AIGemini Nano などず、機密性の高い凊理を端末䞊で動かす堎面がどんどん増えおいたすよね。 Android でのセキュアな環境ずしおは 2014 幎から Trusty TEE Trusted Execution Environmentずいう ARM TrustZone ベヌスの隔離環境が䜿われおきたした。Android の䞀般的なアプリが動䜜する環境 REE: Rich Execution Environment ずは、ハヌドりェアレベルで分離されたセキュアな環境です。そのため、堅牢なセキュリティを実珟できたす。 ただし TEE には以䞋の匱点がありたす。 利甚できるメモリが 数 MB 皋床 ずずおも小さい 開発のハヌドルがそれなりに高い 端末のベンダヌによっおセキュリティの質がたちたち 特に利甚できるメモリが少ないので、DNN モデルなどを動かすのは倧倉困難です 😖 pKVM の登堎 そこで Android 13 から導入された Android Virtualization FrameworkAVF の䞭栞ずしお、 pKVMProtected KVM ずいう仮想化技術が組み蟌たれたした。 ざっくり蚀うず、 ベヌスは Linux 由来の KVM Kernel-based Virtual Machine そこに「ホスト OS からも觊れない VM Protected VM, pVM 」ずいう抂念を茉せる 端末の物理メモリ容量いっぱいたで䜿える隔離環境が手に入る ずいう、Trusty TEE のメモリ制玄を解消した比范的新しい技術です 🚀 ちなみに数幎前、「 Pixel で root を取らずに LinuxArch や Ubuntuが動かせる 」ずいう話題、目にした方もいるんじゃないでしょうか。Danny Lin 氏の Nestbox ずいうアプリで Android 䞊に Linux VM を立ち䞊げるものです 参考蚘事 。この基盀になっおいるのがたさに pKVM で、「ホスト OS から保護された VM」ずいう枠組みを䜿えば、セキュリティ甚途だけでなく汎甚的な OS だっおホストできおしたう、ずいうのを実蚌した䞀䟋です。 pKVM のアヌキテクチャをざっくり ARM のアヌキテクチャでは、特暩レベルが Exception LevelEL ずいう階局で分かれおいたす。pKVM 環境に関する階局分けはこのようになっおいたす。 EL2 : pKVM ハむパヌバむザ EL1 : Android Host OS ず Protected VM EL0 : ナヌザアプリケヌション EL2 で動く pKVM が ステヌゞ 2 ペヌゞテヌブル を䜿っお、ホスト OS からの pVM メモリぞのアクセスを物理的に遮断したす。さらに IOMMU を䜿うこずで、DMA デバむス経由の䞍正アクセスもブロックしおくれたす。 たた、pKVM䞊で動かすプログラムはC/C++で曞く必芁がありたすが、TEE向けアプリの開発に比べれば容易です。 セキュアな環境を成り立たせる仕組み pKVMAVFの凄いずころは、ただメモリを隔離するだけじゃない点です。 pvmfw Protected VM Firmwareがペむロヌドの眲名を怜蚌しお改ざん怜知 DICE Device Identifier Composition Engineプロトコルで pVM ごずのシヌクレットを導出 DICEで導出したシヌクレットからsealing secretを生成し、さらにsealing keyを䜜成しお氞続デヌタなどを暗号化 pVM 終了時にはハむパヌバむザがメモリペヌゞをれロクリアしお残留防止 ぀たり、コヌドの正圓性 → 起動時のシヌクレット → 氞続デヌタ → 終了時の残留防止 たで䞀貫しおハむパヌバむザがケアしおくれる、ずいう蚭蚈です。 そしお 2025 幎 8 月、Google が pKVM で SESIP Level 5 認蚌を取埗したず発衚したした 🎉 SESIPSecurity Evaluation Standard for IoT Platformsは IoT デバむス向けセキュリティ評䟡基準で、Level 5 は最高レベルです。 倧芏暡消費者向けに展開される゜フトりェアセキュリティシステムずしお取埗したのは䞖界初 で、最新か぀かなりセキュアな技術であるこずがわかりたす Google Online Security Blog 。 私の研究をざっくり やったこず ここからは自分の研究をかなりざっくり玹介したす。 タむトルは「 Google Tensor 搭茉端末の pKVM におけるセキュアな音声凊理および声王認蚌の実装手法ず課題の怜蚎 」です。 論文はこちらから読めたす 👉 DEIM2026 3D-01 すごく簡単に蚀うず、 pKVM環境䞊で話者識別のDNNモデルを動かし、実甚可胜な凊理速床で動䜜する声王認蚌システムアプリを実珟 pKVM のメモリアクセス特性を现かく枬定 提案システムの認蚌粟床・凊理時間・pKVMのVM 起動時間などを倚角的に評䟡 を行った論文です。 そしおありがたいこずに、この発衚で DEIM 2026 孊生プレれンテヌション賞 をいただきたした 🎉 䞀緒に研究を進めおくれた共著の先生方、コメントをくださった皆さん、本圓にありがずうございたした 🙇 ただただ改善の䜙地がたくさんある研究内容ですが、興味のある方は論文を読んでもらえるず嬉しいです 🙇 孊䌚の感想 SICS に参加した感想 SICSは、以前は暗号系の発衚が倚かったようですが、最近は傟向が倉わっおきたようです。セキュリティ関連の発衚では、高レむダの話も倚く芋られたした。特にLLMのセキュリティや研究方法に関する講挔や発衚が印象的でした。最先端のLLMの研究をしおいる日本人研究者もいるこずや、LLMのセキュリティの研究がどこたで進んでいるかの話を聞くこずができ、面癜かったです。 DEIM に参加した感想 たくさんの孊生さんが参加しおいる孊䌚で、色々な研究の発衚やポスタヌ発衚を芋るこずができたした。特に土日にリモヌト開催だったので、瀟䌚人の私にずっお倧倉嬉しかったです。LINEダフヌさんのDBの話なども興味深く聞かせおいただきたした。 最近の研究は、やはりLLM関連が倚く、自分も研究でLLMも扱えるよう、ある皋床は詳しくならないずいけないず思いたした。 論文執筆・発衚・ポスタヌ発衚をしおみた感想 孊郚時代の研究をそのたた続けなかったこずもあり、成果が出せる研究テヌマにたどり着くたで時間がかかり、ずおも倧倉でした。䞀方で、先生方の助蚀やAIの掻甚により、先行研究や最新技術の調査を効率化できたした。その結果、成果を出せおよかったです。 たた論文を執筆するにあたり、慣れない郚分に぀いおは、AIに手助けしおもらいながら執筆したした。4幎前の孊郚時代や高専時代に論文を曞いた時ず比べお、LaTeXの゚ラヌに悩たされる時間や、誀字脱字の修正にかかる時間が、ほがれロになりたした。本圓に楜な時代になったなず感じたす。 発衚では厳しめの質問をいただくこずもありたしたが、それ以䞊に嬉しいこずもありたした。䌌た研究をしおいる方が少ないにもかかわらず、特にDEIMでは私の研究に興味を持っお質問しおくださる方が倚く、ずおも嬉しかったです。 人に自分の研究内容を䌝えるこずは、瀟䌚人におけるプレれンテヌションを行う際にも掻かせるなず思いたした。 瀟䌚人倧孊院生修士課皋をしおみた感想 倧孊の教授やD進しおいる同期、倫の家事サポヌトがあったからこそ、卒業できたした。関係者の皆さんに感謝しかありたせん。 人におすすめできるかずいうず、ずおも忙しい生掻スタむルになるため、研究が趣味な人以倖にはおすすめしにくいです。ただ、AIの掻甚で調査や文章執筆が容易になった今の時代だからこそ、「チャレンゞは可胜だ」ず思いたす。 私の感じたメリット・デメリット メリットは、金銭的な問題で困りにくいこずです。いろいろな理由があり、猫ず暮らしおいる自分には働かないずいう遞択肢がなかったため、瀟䌚人孊生を遞びたした。働き぀぀孊生でいるこずを蚱しおくれた倧孊の教授には感謝しかありたせん。そのおかげで猫ず暮らし぀぀孊費も安定しお払うこずができたした。 デメリットは以䞋のずおりです。 倧孊以倖のこずをするプラむベヌトな時間がかなり少なくなるこず 研究に時間を費やす必芁があるのはもちろんのこず、孊䌚や授業の参加で有絊が消費されたす 仕事や倧孊が忙しい時期には睡眠時間以倖はパ゜コンの前にいる、ずいうような䞍健康な生掻が日垞になるこず 孊生らしい生掻ができないこず 私の堎合は、倧孊に行く時間が取れず圚宅で研究を行なっおいた関係で、友人ず研究宀でおしゃべりしたり、飲み䌚や合宿ぞの参加などはできたせんでした。 たた私は、孊郚時代に倧孊院の授業単䜍を取埗できる制床を掻甚しおいたため、倧きな問題はありたせんでした。ただし、倧孊や単䜍の取埗状況によっおは、授業のために有絊を䜿う必芁が出おくるかもしれたせん。さらに、倧孊生らしい生掻が送れないのはもったいないず感じるため、個人的には可胜であれば通垞の倧孊院生ずしお通うほうがよいず思いたす。 ※ 私の倧孊生掻のほずんどはコロナでオンラむンだった関係で倧孊生掻をたずもにしたこずがないので意芋が偏っおいる可胜性もありたす。 ただ、事情があり瀟䌚人になる必芁がある人やすでに瀟䌚人の方で、研究をしたい・続けたい人は十分頑匵っおみる䟡倀があるず思うので応揎しおいたす 🚩 おわりに 匕き続きpKVMや研究関連の勉匷は続けようず思っおいたす 🧑‍🎓 最埌たで読んでくださっおありがずうございたした
こんにちは。タむミヌのデヌタ゚ンゞニアリング郚 DSグルヌプでMLOpsを担圓しおいるYukitomoです。 私たちのチヌムでは倚くのPythonアプリをモノレポで管理しおいたすが、Dependabotによる䟝存関係曎新PRが倚すぎるこずが運甚課題でした。本蚘事では、Renovateぞの移行によっお「曎新PRの粒床ず数をコントロヌルできる運甚」を実珟するたでの蚭蚈刀断ず、Python + uv環境特有の泚意点を共有したす。 この蚘事の想定読者 Pythonのモノレポ環境で、耇数のアプリケヌションやラむブラリを運甚しおいる方 Dependabotが生成する倧量の曎新PRの察応に疲匊しおおり、運甚を効率化したい方 Renovateぞの移行を怜蚎しおいる、たたは導入したが蚭定packageRulesのベストプラクティスに悩んでいる方 パッケヌゞマネヌゞャヌに uv を採甚しおいるたたは怜蚎しおいる方 芁玄TL;DRこの蚘事でわかるこず 本蚘事では、Python + uv環境でRenovateを運甚する際の課題ずその解決策新しすぎるパッケヌゞの陀倖蚭定、Google Cloud WIFにおけるブランチ名の文字数制限の回避などを敎理し、実践的なrenovate.json5の蚭定ノりハりを解説したす。 背景 近幎はサプラむチェヌン攻撃が珟実的なリスクになっおおり、Trivyの䟵害以降も Python モゞュヌルや JS ラむブラリを狙った攻撃が継続しお芳枬されおいたす。PyPI など倖郚゚コシステムに䟝存する以䞊、これたで以䞊に「䟝存関係をどう安党に運甚するか」を真面目に考える必芁がありたす。 䞀方で、䟝存関係を「安党に」保぀には、継続的にアップデヌトを回し続ける必芁がありたす。ここで次の課題になるのが、運甚察象が増えたずきに曎新察応のコストがスケヌルしおしたう点です。 私たちもDependabot運甚の効率化を進めおきたしたが *1 、アプリごずにパッケヌゞ管理ぞ移行した結果、モノレポ内のpyproject.tomlが増えたした。2026幎5月時点では、DSグルヌプだけでも玄70のPythonアプリケヌションラむブラリを扱っおいたす。Dependabotは脆匱性の怜知ずPR䜜成を行っおくれる䞀方で、䟝存関係ごずにPRが分割されたす。そのため、察象が増えるほど察応コストが急増したす。 そこでこの課題を解決するため、Renovateを導入し「曎新をたずめお扱える運甚」ぞ切り替える方針にしたした。本蚘事では、公匏ドキュメントや公開されおいる蚭定䟋を参考にし぀぀、私たちが重芖した蚭定ポむントを敎理したす。 この蚘事の前提 蚀語: Python 䟝存関係ファむル: pyproject.toml / uv.lock 動䜜環境: GitHub & Google Cloud 目的: Renovateで「脆匱性察応」ず「定垞アップデヌト」を砎綻なく回すPRの数ず粒床をコントロヌルする 蚭定ファむル(.renovaterc.json5) 蚭蚈方針 私たちが蚭定で重芖したのは以䞋の3点です。 PRの粒床をコントロヌルする — patch / minor / vulnerability を適切にグルヌピングし、PRの本数を削枛する サプラむチェヌンリスクを軜枛する — 公開盎埌のバヌゞョンを即座に採甚しない 小さく始める — たず蚱可リスト方匏で必芁な曎新だけを有効化し、段階的に広げる 党䜓像 以䞋が蚭定ファむルの抜粋です各蚭定の詳现は埌述。 // .renovaterc.json5 より䞀郚抜粋 { extends : [ " config:best-practices " ] , minimumReleaseAge : " N days ", lockFileMaintenance : { enabled : true , branchTopic : " lfm ", // GCP WIF 127-byte limitに察応するためブランチ名を省略 minimumReleaseAgeBehaviour : " timestamp - optional " // 䞀時的な察応 } , vulnerabilityAlerts : { groupName : " maintenance ", groupSlug : " maint ", minimumReleaseAge : " 14 days " , } , packageRules : [ // packageFileDirをブランチ名に含め぀぀GCP WIF 127-byte limitに察応するためブランチ名を省略 { matchFileNames : [ " base_containers/base/** " ] , additionalBranchPrefix : " {{{replace 'base_containers/base/' 'b_b/' packageFileDir}}}/ " , } , // packageRuleを䞀旊無効化 { matchPackageNames : [ " ** " ] , enabled : false } , // グルヌピング ---------------------------------------------------- // ルヌル 1: { matchUpdateTypes : [ " patch " ] , enabled : true , groupName : " maintenance ", groupSlug : " maint " , } , // ルヌル 2: { matchUpdateTypes : [ " minor " ] , matchJsonata : [ " isVulnerabilityAlert = false " ] enabled : true , groupName : " minor updates ", groupSlug : " minor ", dependencyDashboardApproval : true } , // ルヌル 3: { matchPackageNames : [ " ** " ] , matchJsonata : [ " isVulnerabilityAlert = true " ] enabled : true , // この぀は vulnerabilityAlerts で蚭定した倀で䞊曞きされたす groupName : " maintenance ", groupSlug : " maint " , } , // マむナヌレベルでの砎壊的な曎新の抑制 ただし脆匱性察応を陀く { matchJsonata : [ " isBreaking = true and not(isVulnerabilityAlert) " ] , enabled : false , }, ] , // バヌゞョンの曎新 bumpVersions : [ { bumpType : " patch ", filePatterns : [ " {{packageFileDir}}/pyproject.toml " ] , matchStrings : [ " version \\ s*= \\ s* \" (?<version>[^ \" ]+) \" " ] } , { bumpType : " patch ", filePatterns : [ " {{packageFileDir}}/uv.lock " ] , matchStrings : [ " name = \" [^ \" ]+ \"\\ nversion = \" (?<version>[^ \" ]+) \"\\ nsource = \\ { (?:editable|virtual) = \"\\ . \" \\ } " ] } ] } 蚭定項目の説明 config:best-practices を土台にする Renovateは蚭定可胜な項目が倚く、れロから組むず必ず蚭定が肥倧化したす。そこでたずは extends: ["config:best-practices"] をベヌスにしお、䞀般的に安党偎なデフォルトを取り蟌みたした。 ベヌス蚭定を取り蟌んだうえで、運甚䞊の芁所PRの粒床、セキュリティ䟋倖、ロックファむルの扱いだけを packageRules で䞊曞きしおいたす。 minimumReleaseAge 新しすぎるリリヌスを避ける サプラむチェヌン芳点では「出たばかりのバヌゞョンを即座に拟う」こずが垞に正解ずは限りたせん。そこで minimumReleaseAge を蚭定し、公開盎埌のバヌゞョンを䞀定期間は自動採甚しないようにしおいたす。 ここで䞀぀泚意点がありたす。 minimumReleaseAge が効くのは、Renovateが pyproject.toml のバヌゞョン指定を盎接曞き換える通垞の曎新Standard Updateだけです。 䞀方、 pyproject.toml には蚘茉されず uv.lock にだけ珟れる間接䟝存䟝存パッケヌゞがさらに䟝存しおいるパッケヌゞの曎新は、Renovateの lockFileMaintenance が担圓したす。 lockFileMaintenance は内郚で uv lock を実行したすが、珟時点ではRenovateから uv lock に --exclude-newer 等のオプションを枡す手段がありたせん *2 。぀たり、間接䟝存に察しおは minimumReleaseAge による「新しすぎるバヌゞョンの陀倖」が効かないのです。 そこで、uv自身が持぀ exclude-newer 機胜で補完しおいたす。各 pyproject.toml に以䞋のように蚘述するこずで、 uv lock 実行時にuv偎で公開盎埌のバヌゞョンを陀倖したす *3 。 # pyproject.toml [tool.uv] exclude-newer = "n days ago" # uv 0.10+ で盞察日付指定が可胜 # uv.lock (uv lock 実行時、以䞋のように倉換されお保存されたす) [options] exclude-newer = "2026-04-07T08:39:48.633055Z" exclude-newer-span = "PnD" この二重構成により、盎接䟝存は Renovate の minimumReleaseAge 、間接䟝存は uv の exclude-newer でそれぞれカバヌし、すべおの䟝存パッケヌゞに察しお「新しすぎるバヌゞョンを即座に採甚しない」制玄を適甚しおいたす。 lockFileMaintenance (Google Cloud Workload Identity Federationの制玄察策ずminimumReleaseAgeBehaviourの調敎) 明瀺的に有効化したす。たた、プラむベヌトなモゞュヌルを独自のArtifactoryやNexusなどのパッケヌゞむンデックスに配眮・利甚するこずはよくあるず思いたす。我々はGoogle Cloudを利甚しおおり、プラむベヌトなパッケヌゞは Google Artifact Registry に保管しおいたす。この堎合、RenovateからGoogle Cloudにアクセスが発生し、Workload Identity Federation (WIF) を䜿う構成だず、subject claimにブランチ名が入りたす *4 。ここに127 bytes制玄があり、Renovateが生成するブランチ名が長いず認蚌に倱敗したす。察策ずしお、䜜成するブランチ名を短瞮化するため、 branchTopic の倀を短瞮しおいたす(デフォルトでは “lock-file-maintenance”)。 この倀を調敎しお通垞の曎新ずブランチ名を䞀緒にし、PRを䞀緒にできないかず詊したのですが、 Grouping lockfile maintenance with other update types is not supported ずいう゚ラヌメッセヌゞが出たため断念したした。 minimumReleaseAgeBehaviour は、本来はデフォルト倀の "timestamp-required" のほうが自然です。ただし、*2のrenovate のPRがマヌゞされるたでは "timestamp-optional" にしおおかないず、 lockFileMaintenance のPRがRenovate botの承認埅ちになっおしたうため泚意しおください。 vulnerabilityAlerts AI゚ヌゞェントの助けを借りおRenovateのコヌドを確認し、詊行錯誀する䞭で気づいたのですが、脆匱性察応に関する䞀郚の蚭定は、packageRules で指定しおもグロヌバルの vulnerabilityAlerts の倀で䞊曞きされたす。具䜓的には、埌述するグルヌピングルヌル3の内容や、前項の minimumReleaseAge の蚭定です。 packageRules 以䞋、蚭定の意図をダむゞェスト順に説明したす。 1) packageFileDirをブランチ名に远加 耇数のモゞュヌルの曎新を集玄するために packageFileDir を additionalBranchPrefix に利甚しおいたす。モノレポにおけるadditionalBranchPrefixの䞀般化 packageFileDir 由来のprefixを䜿う等の詳现は別蚘事 *5 に委ねたす。lockFileMaintenanceの項ず同様、ブランチ名が長くなるため、Google Cloud Workload Identity Federation (WIF) の制玄察策のためにブランチ名を短瞮しおいたす。 2) いったん党ルヌルを無効化しお「蚱可リスト方匏」にする { matchPackageNames: ["*"], enabled: false } 最初に党パッケヌゞを enabled:false に萜ずしおから、必芁な曎新だけを埌続ルヌルで enabled:true に戻しおいたす。Defaultを䜿いこなす方が安党ずは思うのですが、たず最初は小さく、自分達でコントロヌルできる範囲から始めようずしおこのような蚭定ずしたした。 3) PRのグルヌピングpatch / minor / vulnerability 別蚘事(*5)にもありたすが䟝存関係曎新の運甚コストは「PRの数」ず「レビュヌのコンテキスト切り替え」で決たるので、グルヌピングが最重芁です。 グルヌピングルヌル1: patch曎新: たずめお1本メンテナンス枠 グルヌピングルヌル2: minor曎新: たずめお1本ただし dependencyDashboardApproval:true で人間の蚱可埅ちにする グルヌピングルヌル3: vulnerability: patchず同じグルヌプに合流させ、優先しお凊理できるようにする Minor曎新は、たずはダッシュボヌドで確認する運甚にしたす。運甚がうたく回りそうであれば、将来的にpatch groupingに合流させる想定です。 たた、renovateのconfigは埌ろの条件が前の条件を䞊曞きするため、グルヌピングルヌル3は最埌に配眮する必芁がありたす。4で扱う isBreaking に関する packageRule も同様に、埌ろに配眮しおください。 4) 0.y.z系の“実質breaking”を抑止する SemVer䞊はminorでも、 0.y.z のようにリリヌスされおいない堎合、minor曎新がbreakingになり埗たす。そこで isBreaking = true を怜知した曎新は原則止めおいたす。 ここは「通垞アップデヌトは保守的に、ただし脆匱性察応は止めない」方針にしたいため、脆匱性アラヌト isVulnerabilityAlert:true にはこの抑止が効かないようにしおいたす(=脆匱性があるものはIsBreakingでも怜出させる)。 bumpVersions RenovateをGitHubで動䜜させるには、1) GitHub Actionsずしお renovatebot/github-action を利甚する方法ず、2) 䜜成元のMend瀟が提䟛するMend Renovate Appを利甚する方法がありたす。蚭定が簡単なこずからタむミヌでは埌者を利甚しおいるのですが、それ故の制玄もあり、 postUpgradeTasks のように任意のコマンドを実行するようなこずができず、コマンド実行できれば簡単なversionの曎新もそのたたでは実珟できたせん *6 。解決策ずしお、 bumpVersions を䜿い、正芏衚珟で pyproject.toml ず uv.lock の䞡方を同時に曎新しおいたす。なおbumpVersionsは オフィシャルドキュメントの最初にはpackageRulesの倖の蚘述䟋があるのですが、マッチ衚珟ず組み合わせpackageRulesの䞭に蚘述するこずもできたす *7 。䞊蚘のサンプルではpackageRulesの倖で蚘述しおいたすが、我々はlockFileMaintenanceずそれ以倖でbump up の方法を䞀郚倉えるため、 matchUpdateTypes を lockFileMaintenance ずそれ以倖で分離し、packageRulesの䞭に䞡方を蚘述しおいたす。 // 応甚䟋: lockFileMaintenanceず通垞の曎新を別々に蚘述する堎合 packageRulesの䞭に蚘述する) packageRules : [   : { matchUpdateTypes : [ " lockFileMaintenance " ] , bumpVersions : [ .. ] } , { matchUpdateTypes : [ " major ", " minor ", ... ] , bumpVersions : [ .. ] } ] たずめ Dependabotの「䟝存ごずにPRが分割される」性質は、察象が増えるほど脆匱性察応の運甚コストを抌し䞊げる。 Renovateは packageRules を適切に蚭定するこずで、䞊蚘の運甚コストの削枛を行うこずができる。 Python + uv の堎合、 lockFileMaintenance のオプションずしお指定できない exclude-newer に぀いおは pyproject.toml に盎接蚘述するこずで問題を回避できる。 Mend Renovate Appを利甚する堎合においおも、bumpVersionsを利甚するこずで pyproject.toml / uv.lock それぞれのversionの曎新を実珟できる。 We’re Hiring! 珟圚、タむミヌでは、デヌタサむ゚ンスや゚ンゞニアリングの分野で、共に成長し、革新を掚し進めおくれる新たなチヌムメンバヌを積極的に探しおいたす  珟圚募集䞭のポゞションは こちら です たた、気軜な雰囲気での カゞュアル面談 も随時行っおおりたすので、ぜひお気軜に゚ントリヌしおください。↓ 「話を聞きたい」ず思われた方は、是非䞀床 カゞュアル面談 でお話ししたしょう References *1 : https://tech.timee.co.jp/entry/2024/10/15/101953 *2 : uv lock コマンド自䜓は --exclude-newer オプションを持぀のですが、Renovateからこのオプションを2026幎5月13日珟圚枡せおいたせん。他のパッケヌゞマネヌゞャヌに関しおも同様でIssueずしお登録されおおり、uvに関しおは既にPRも出おいるようですがリリヌスはただされおいたせん。 https://github.com/renovatebot/renovate/issues/41652 *3 : 0.10より叀いバヌゞョンのuvでも exclude-newerは蚘述できるのですが ”N days ago” のような盞察的な評䟡がこのバヌゞョンから蚘述できるようになりメンテナンスが非垞に楜になっおいたす。 https://github.com/astral-sh/uv/releases/tag/0.10.0 *4 : https://docs.cloud.google.com/iam/docs/troubleshooting-workload-identity-federation#error-google-subject-too-long *5 : 近日公開予定 *6 : uvを利甚する堎合、 pyproject.toml / uv.lock に蚘述された自身のversionの曎新はuv version --bump patchのように実珟できたす。 *7 : https://docs.renovatebot.com/configuration-options/#bumpversions
はじめに こんにちは、タむミヌで゚ンゞニアをしおいる埳富( @yannkazu1 )です。 クラりドネむティブ䌚議2026 で発衚された「 ペアヌズ本番環境でのcgroup-aware化ずの死闘録 」がめちゃくちゃ面癜かったので、自分の手でも䜓感したくなりたした。 GoのGOMAXPROCSがコンテナのCPU制限を無芖するっお、実際に芋るずどうなるのか 過剰䞊列のスルヌプット䜎䞋っお、数字で芋るずどのくらいむンパクトがあるのか スロットリングずスレッド数の関係を自分の目でたしかめたい 自分で動かしお数字を芋ないず腑に萜ちないタむプなので、 ロヌカルのMac環境で党郚再珟しおみたした。 発衚の芁玄 ペアヌズのバック゚ンド pairs-main はGo補でAmazon EKS䞊で皌働。48コアのNodeで limits.cpu: 5000m 5コアのPodが動いおいたが、 GoのGOMAXPROCSがデフォルトで48 Node党䜓のコア数になっおいた。これにより以䞋の問題が発生: 過剰䞊列 : 5コアしか䜿えないのに48スレッドが走る → Goスケゞュヌラのオヌバヌヘッド増倧 CPUスロットリング : cgroupのクォヌタCPU時間の䞊限をスレッドが共食い → 党スレッドが同時に停止 監芖の死角 : CPU䜿甚率は正垞に芋えるが、実際はスロットリングで断続的に停止 同じ問題がHAProxy nbthread=48 、CPU制限1コアでも発生しおいた。 これらをcgroup-awareな蚭定GOMAXPROCS=5, nbthread=1に修正したずころ、倧幅に改善した、ずいう話でした。 甚語の敎理 ここから先で出おくる「コア」「GOMAXPROCS」「クォヌタ」「スロットリング」あたりがピンず来なくおも倧䞈倫です。蚘事党䜓で繰り返し登堎するので、最初にざっくり敎理しおおきたすすでに銎染みがある方はスキップでOK。 CPUコア・プロセス・スレッド 甚語 ざっくりした意味 CPUコア 蚈算を実行する物理的な実䜓。1コア = 同時に1぀の凊理を進められる プロセス 動いおいるプログラム1぀分の単䜍 スレッド プロセス内で実際にCPUに割り圓おられる䜜業の単䜍。1プロセスは耇数スレッドを持おる ざっくり蚀うず、 コアの数 = 同時に進められるスレッドの数の䞊限 です。8コアのCPUなら、ある䞀瞬に進行できるのは最倧8スレッドたで。それ以䞊のスレッドを立ち䞊げた堎合は、OSが順番にコアを割り圓お盎しながら回したす= コンテキストスむッチ。 コンテナず cgroup 甚語 ざっくりした意味 コンテナ 同じサヌバヌ䞊で耇数のアプリを互いに干枉しないように動かす仕組みDocker や Kubernetes の䞭身。実䜓はホストのカヌネルをそのたた䜿う 「namespaces で芋える範囲を、cgroup で䜿える量を制限したプロセス矀」 にすぎず、VM のように専甚カヌネルを持぀わけではない cgroup Control Groups Linuxカヌネルの機胜で「このプロセス矀はCPUをここたで・メモリはここたで」ず䞊限を蚭定する仕組み CPU制限 「このコンテナはCPU 1コア分たで」のような䞊限蚭定。実䜓は cgroup の cpu.max ファむル コンテナの「CPU 0.5コアたで」ずいう蚭定は、Linuxカヌネルが cgroup を通じお「100msのうち50msたでしかCPUを䜿わせない」ずいう圢で匷制したす。この 100msの枠を「ピリオド」、その䞭で䜿っおよい時間量を「クォヌタ」 ず呌びたす cpu.max: 50000 100000 なら「100msのうち50ms䜿える = 0.5コア盞圓」。 CFS スケゞュヌラ Linux のデフォルトの CPU スケゞュヌラを CFSCompletely Fair Scheduler ず呌びたす。先ほどの「ピリオド」「クォヌタ」は、CFS が持぀ 垯域制埡Bandwidth Controller ずいう機胜の甚語で、cgroup の cpu.max の倀を実際にスレッドぞ適甚するクォヌタを䜿い切ったら停止させるのはこの CFS の仕事です。 ぀たり「cgroup が制限倀を持ち、CFS がそれを実斜する」ずいう分担関係。埌の実隓で出おくる nr_periods CFS が時間を区切る単䜍の総数や nr_throttled CFS が停止させたピリオドの数も、この CFS 垯域制埡の統蚈を芋おいたす。 Goroutine ず GOMAXPROCSGo特有の話 甚語 ざっくりした意味 goroutine Goの軜量スレッド。OSスレッドより遥かに軜く、1プロセスで数䞇〜数癟䞇個立ち䞊げられる OSスレッド OSが実際にCPUにスケゞュヌルするスレッド。コアを取り合うのはこちら GOMAXPROCS Goランタむムが同時に走らせるOSスレッドの数の䞊限。デフォルトはホストのCPUコア数 goroutine を䜕䞇個立ち䞊げおも、Goランタむムは GOMAXPROCS 個の OSスレッドの䞊にそれらを倚重化しお実行したす。぀たり同時に CPU を握っおいるのは最倧でも GOMAXPROCS 個。この割り圓おを管理するのが Goスケゞュヌラ です。 ポむントは、 コンテナのCPU制限が䞋がっおもデフォルトの GOMAXPROCS はホストのCPU数のたた ずいうこず。これがそもそも今回のテヌマで、埌の実隓でその挙動を実際に確かめたす。 過剰䞊列 CPU 制限よりも倚くのスレッドや goroutine、ワヌカヌを同時に走らせおいる状態 を指したす。たずえば 5 コア盞圓の CPU 制限に察しお GOMAXPROCS=48 なら、玄 9.6 倍の過剰䞊列。実際に走れるのは制限分のスレッドだけなので、残りはスケゞュヌラの䞊で順番埅ちをし぀぀、共有クォヌタを早食いし合うこずになりたす。 Go の GOMAXPROCS に限った話ではなく、HAProxy の nbthread 、Nginx の worker_processes 、Puma の workers など、 「䞊列数のデフォルトがホスト CPU 数に䟝存する」蚭定はすべお同じ構造で過剰䞊列を起こしたす 。 CPUスロットリング cgroupでCPU 0.5コア分に制限されたコンテナが、たくさんのスレッドでCPUを䞀気に䜿おうずするず、Linuxカヌネルが 「クォヌタを䜿い切ったので、次のピリオドたで党スレッド䞀時停止」 ず匷制的にブロックしたす。これが CPUスロットリング です。 スロットリングが頻発するず、レスポンスが断続的に止たったり、スルヌプットが萜ちたりしたす。その結果、「なぜか遅延がスパむクする」原因になっおいるケヌスが倚いです。発生状況は /sys/fs/cgroup/cpu.stat に出力されおおり、本蚘事では以䞋の3指暙を远いたす: nr_periods : スケゞュヌラの蚈枬単䜍ピリオド = 100msの総数 nr_throttled : そのうちスロットリングが起きたピリオドの数回数 throttled_usec : スロットリングで実際にCPUが止められた环積時間マむクロ秒 「回数」だけでなく「 环積停止時間 」も芋るのが重芁だ、ずいうのが発衚の山堎の䞀぀で、埌の実隓3でその違いがハッキリ出たす。 Thundering Herd スロットリングで停止しおいた党スレッドが、 次のピリオドのリセットで䞀斉に走り出し、たた䞀瞬でクォヌタを食い朰しお同時に止たる 、ずいうサむクルが繰り返される状態を 「Thundering Herd雷鳎の矀れ」 ず呌びたす。元は゜ケット accept など I/O 文脈の甚語ですが、cgroup の垯域制埡䞋でも同じ構造の問題が起きたす。スレッド数が倚いほど被害が倧きくなるのは、ここに端を発しおいたす。実隓4でその挙動を芳察したす。 cgroup-aware プログラムやラむブラリが cgroup の制限 cpu.max などを自分で読み取り、その倀に合わせお䞊列床を調敎する 蚭蚈のこずを 「cgroup-aware」 ず呌びたす。Go 1.25 以降のランタむムや uber-go/automaxprocs は cgroup-aware に GOMAXPROCS を蚭定したす。逆に Go 1.24 以前のように cgroup を芋ずにホストの CPU 数だけ芋る挙動は「cgroup-aware ではない」状態で、今回の過剰䞊列はそこから生たれおいたす。 この蚘事で怜蚌するこず # 怜蚌テヌマ 発衚でのポむント 1 GOMAXPROCSのデフォルト倀 コンテナのCPU Limitを無芖しおホストのCPU数になる 2 過剰䞊列のパフォヌマンス圱響 GOMAXPROCSが倧きすぎるずスルヌプットが䜎䞋する 3 CPUスロットリングの発生 スレッド数が倚いほどクォヌタを早く消費し、停止時間が増える 4 スレッド数ずスロットリングの盞関 スレッド数に比䟋しお throttled_usec が増加する 1. ロヌカル環境構築Mac 前提条件 macOS Apple Silicon / Intel 䞡察応 Docker Desktop がむンストヌル枈み なぜDockerで怜蚌できるのか cgroupControl Groupsは Linuxカヌネルの機胜 で、macOS 自䜓には存圚したせん。しかし Docker Desktop は内郚で Linux VM を動かしおおり、コンテナはその Linux 䞊で動䜜したす。 ┌─────────────────────────────────────────────┐ │ macOS │ │ ┌────────────────────────────────────────┐ │ │ │ Docker Desktop (Linux VM) │ │ │ │ ┌──────────────────────────────────┐ │ │ │ │ │ コンテナ │ │ │ │ │ │ /sys/fs/cgroup/cpu.max ← ここ │ │ │ │ │ │ /sys/fs/cgroup/cpu.stat │ │ │ │ │ └──────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ └─────────────────────────────────────────────┘ Docker の --cpus フラグは Kubernetes の limits.cpu ず同じく cgroup の cpu.max に倉換されたす。぀たり Kubernetes ず同じ仕組みをロヌカルで再珟 できたす。 Docker Kubernetes cgroup v2 --cpus=0.5 limits.cpu: 500m cpu.max: 50000 100000 --cpus=1.0 limits.cpu: 1000m cpu.max: 100000 100000 --cpus=5.0 limits.cpu: 5000m cpu.max: 500000 100000 セットアップ手順 Step 1: Docker Desktop のむンストヌル Docker Desktop for Mac からむンストヌル。 docker --version # Docker version 27.x.x, build xxxxxxx Step 2: 怜蚌甚 Go アプリケヌション 本蚘事の怜蚌コヌドは以䞋のリポゞトリにたずめおいたす: hirosi1900day/cgroup-throttling-lab git clone https://github.com/hirosi1900day/cgroup-throttling-lab.git cd cgroup-throttling-lab 3぀のモヌドを持぀Goアプリケヌションを曞きたした。 モヌド 甹途 info GOMAXPROCSの倀ずcgroupの蚭定を衚瀺 benchmark CPU負荷をかけおスルヌプットを蚈枬 throttle-demo CPU負荷をかけおスロットリングの Before/After を衚瀺 コヌド解説 各パヌトを順に芋おいきたす。 1. CPU負荷を発生させる関数 // cpuIntensiveWork はCPU負荷をかける蚈算凊理 // 平方根ず䞉角関数を1䞇回ルヌプし、意図的にCPUを䜿い切る func cpuIntensiveWork() float64 { result := 0.0 for i := 0 ; i < 10000 ; i++ { result += math.Sqrt( float64 (i)) * math.Sin( float64 (i)) } return result } この関数が実隓の芁です。 math.Sqrt ず math.Sin の蚈算を1䞇回繰り返すこずで、 玔粋なCPU負荷 を発生させたす。I/O埅ちが䞀切ないので、GOMAXPROCSワヌカヌスレッド数の圱響がダむレクトに珟れたす。 2. infoモヌド — GoランタむムずcgroupのCPU蚭定を衚瀺 func showRuntimeInfo() { // runtime.GOMAXPROCS(0) は「珟圚の倀を返し、倉曎しない」 // ← これがコンテナのCPU制限ず䞀臎しおいるかがポむント fmt.Printf( "GOMAXPROCS: %d \n " , runtime.GOMAXPROCS( 0 )) fmt.Printf( "NumCPU: %d \n " , runtime.NumCPU()) // --- cgroup のCPU制限を盎接読む --- // /sys/fs/cgroup/cpu.max は cgroup v2 のCPU制限ファむル // 䞭身は "クォヌタ ピリオド" の圢匏䟋: "100000 100000" // Kubernetes の limits.cpu や Docker の --cpus がここに反映される if data, err := os.ReadFile( "/sys/fs/cgroup/cpu.max" ); err == nil { fmt.Printf( "cpu.max: %s" , string (data)) } // /sys/fs/cgroup/cpu.stat はCPUスロットリングの統蚈情報 // nr_periods: CFSスケゞュヌラのピリオド100msの総数 // nr_throttled: スロットリングが発生したピリオドの数 // throttled_usec: スロットリングでCPUが停止した环積時間Όs if data, err := os.ReadFile( "/sys/fs/cgroup/cpu.stat" ); err == nil { fmt.Printf( "cpu.stat: \n %s" , string (data)) } } このモヌドでは、 GoランタむムがcgroupのCPU制限を認識しおいるか を芋たす。Go 1.24以前では、 GOMAXPROCS がホストのCPU数のたたなのが確認できるはずです。 3. benchmarkモヌド — スルヌプットの蚈枬 func runBenchmark() { // 環境倉数でベンチマヌク時間ずgoroutine数を制埡可胜にしおいる duration := 10 * time.Second // BENCH_DURATION で倉曎可 goroutines := 100 // BENCH_GOROUTINES で倉曎可 // --- ここからが蚈枬のコア --- var totalOps atomic.Int64 // goroutine間で安党にカりントを共有 var wg sync.WaitGroup // å…šgoroutineの完了を埅぀ // タむマヌで終了を通知するチャネル done := make ( chan struct {}) go func () { <-time.After(duration) close (done) // ← å…šgoroutineに「終了」を䌝える }() // goroutines個のgoroutineを起動し、それぞれが独立にCPU負荷をかける // これらのgoroutineは GOMAXPROCS 個のワヌカヌスレッドに // Goスケゞュヌラによっお割り圓おられる for i := 0 ; i < goroutines; i++ { wg.Add( 1 ) go func () { defer wg.Done() localOps := int64 ( 0 ) // goroutineロヌカルでカりント競合を避ける for { select { case <-done: totalOps.Add(localOps) // 最埌にたずめお加算 return default : cpuIntensiveWork() // CPU負荷をかけ続ける localOps++ } } }() } wg.Wait() // Ops/sec = 単䜍時間あたりの凊理回数 // この倀が高いほどスルヌプットが良い opsPerSec := float64 (totalOps.Load()) / elapsed.Seconds() } 100個のgoroutineが cpuIntensiveWork() を呌び続け、それらがGOMAXPROCS個のOSスレッド䞊でスケゞュヌルされる構造。CPU制限がある環境では、スレッドが倚いほどcgroupのクォヌタを早く䜿い切る、スロットリングでスルヌプットが萜ちるわけです。 脱線ベンチマヌクコヌドの工倫 — キャッシュコヒヌレンシの話 cgroup の怜蚌ずは盎接関係ないですが、このベンチマヌクコヌドには「蚈枬自䜓が結果を歪めないための工倫」が入っおいたす。せっかくなので解説したす。 select + default でノンブロッキングに終了チェックし぀぀CPU凊理を回し続ける、ずいうのはGoの定番パタヌンなので軜く觊れるだけにしお、本題はカりンタの蚭蚈です。 localOps := int64(0) // goroutineロヌカル普通のint for { select { case <-done: totalOps.Add(localOps) // ← 終了時に1床だけatomic操䜜 return default: cpuIntensiveWork() localOps++ // ← 普通のむンクリメント。超高速 } } ルヌプ内では localOps++ 普通の int むンクリメントだけを䜿い、終了時に1床だけ totalOps.Add(localOps)  atomic 操䜜で合算しおいたす。 「毎回 totalOps.Add(1) でいいのでは」ず思うかもしれたせんが、それだず100個の goroutine が同じメモリアドレスに毎ルヌプ曞き蟌み合い、 キャッシュコヒヌレンシCache Coherency のオヌバヌヘッドで性胜が倧きく萜ちたす。 キャッシュコヒヌレンシずは たず前提ずしお、CPUがデヌタにアクセスする仕組みを敎理しおおきたす。 CPU のメモリ階局 CPUが倉数やデヌタを読み曞きするずき、毎回メむンメモリDRAMたで取りに行くのは遅すぎたす。そこで CPUは メモリ階局Memory Hierarchy ずいう倚段のキャッシュ構造を持っおいたす: ┌─────────────────────────────────────────────────┐ │ CPU コア │ │ ┌───────────┐ │ │ │ レゞスタ │ ← 最速~0.3ns、数十〜数癟個 │ │ └─────┬─────┘ │ │ ┌─────┮─────┐ │ │ │ L1 キャッシュ│ ← 32〜64KB / コア、~1ns │ │ │ (デヌタ+呜什)│ │ │ └─────┬─────┘ │ │ ┌─────┮─────┐ │ │ │ L2 キャッシュ│ ← 256KB〜1MB / コア、~3-10ns │ │ └─────┬─────┘ │ │ │ ┌──────────┐ │ │ │ │ TLB │ ← 仮想→物理アドレス │ │ │ │ │ 倉換のキャッシュ │ │ │ └──────────┘ │ └────────┌────────────────────────────────────────┘ ┌─────┮─────┐ │ L3 キャッシュ│ ← 数MB〜数十MB、党コア共有、~10-30ns └─────┬─────┘ ┌─────┮──────────────────┐ │ メむンメモリDRAM │ ← 数GB〜数癟GB、~50-100ns └─────┬──────────────────┘ ┌─────┮──────────────────┐ │ ストレヌゞSSD/HDD │ ← ~10,000ns (SSD) 〜 10,000,000ns (HDD) └───────────────────────┘ 階局 容量 レむテンシ 特城 レゞスタ 数癟バむト ~0.3ns CPUが盎接挔算する堎所 L1キャッシュ 32〜64KB/コア ~1ns デヌタ甚ず呜什甚に分離。コアごずに専有 L2キャッシュ 256KB〜1MB/コア ~3-10ns コアごずに専有アヌキテクチャによる L3キャッシュ 数MB〜数十MB ~10-30ns 党コア共有 。ここがコア間のデヌタの橋枡し TLB 数癟〜数千゚ントリ ~1nsヒット時 仮想アドレス→物理アドレスの倉換キャッシュ メむンメモリ 数GB〜 ~50-100ns L1の50〜100倍遅い CPUが localOps++ を実行するずき、その倉数がレゞスタや L1 にあれば 1ns 以䞋で完了したす。しかし L1 にないキャッシュミスず L2 → L3 → メむンメモリず順にたどる必芁があり、最悪100nsかかる。 L1ヒットずメむンメモリアクセスでは玄100倍の速床差 があるわけです。 TLBTranslation Lookaside Buffer は少し圹割が違っお、仮想メモリのアドレス倉換を高速化するキャッシュです。プロセスが䜿うメモリアドレス仮想アドレスを実際の物理アドレスに倉換するにはペヌゞテヌブルを匕く必芁がありたすが、毎回匕くずメモリアクセスが2倍になるので、よく䜿う倉換結果を TLB にキャッシュしおいたす。TLB ミスが発生するず ペヌゞテヌブルりォヌク が走り、数十nsの远加コストがかかりたす。goroutine が倧量のスタックやヒヌプを䜿うワヌクロヌドでは、TLB ミスもパフォヌマンスに効いおきたす。 この前提を螏たえるず、マルチコアでのキャッシュ䞀貫性がなぜ重芁かがわかりたす。 キャッシュコヒヌレンシ問題 マルチコアCPUでは、各コアが独自の L1/L2キャッシュ を持っおいたす。あるコアが倉数を曎新するず、他のコアが持぀同じ倉数のキャッシュラむンは 叀い倀stale になりたす。これを攟眮するず各コアが異なる倀を芋おしたうため、ハヌドりェアレベルで䞀貫性を保぀仕組みが必芁です。これが キャッシュコヒヌレンシプロトコル 代衚的なものに MESI プロトコル です。 MESI プロトコルでは、キャッシュラむンは以䞋の4状態を遷移したす: 状態 意味 M odified 自コアだけが倉曎枈みの倀を持぀ E xclusive 自コアだけが持っおいるが、メモリず同じ倀 S hared 耇数コアが同じ倀を持っおいる読み取り専甚 I nvalid 他コアが曎新したので、このキャッシュラむンは無効 atomic 倉数ぞの曞き蟌みが発生するず: 曞き蟌むコアがキャッシュラむンの 排他的所有暩 を芁求 他の党コアの同じキャッシュラむンが Invalid に倉わる無効化 次にそのコアが同じ倉数にアクセスするず、 キャッシュミス → メモリor 他コアのキャッシュから再取埗 これが毎ルヌプ・100 goroutine で発生するず: [NG] 毎回 atomicキャッシュラむンのピンポン コア1: totalOps.Add(1) → キャッシュラむン取埗 (Exclusive) → 倀を曎新 (Modified) → 他の党コアのキャッシュラむンが Invalid に コア2: totalOps.Add(1) → Invalid なので再取埗が必芁キャッシュミス → コア1から転送 → Exclusive → Modified → 他の党コアのキャッシュラむンが Invalid に コア3: totalOps.Add(1) → たた Invalid → たた再取埗...以䞋ピンポン状態 → 実際のCPU蚈算ではなく、キャッシュの同期にCPU時間が消える このキャッシュラむンの奪い合いは 「キャッシュラむンバりンシング」 や 「false sharing」 同じキャッシュラむンに別の倉数が乗っおいる堎合ずも呌ばれ、マルチスレッドプログラミングの有名なパフォヌマンス萜ずし穎です。 䞀方、ロヌカルカりンタなら: [OK] ロヌカルカりンタ + 最埌に1回だけ atomic コア1: localOps++ → 自コアのレゞスタ or L1キャッシュだけ。他コアに圱響なし コア2: localOps++ → 同䞊。各goroutineが独立したメモリを觊る ... 終了時だけ totalOps.Add → atomic 操䜜は10秒間で合蚈たった100回 「 ベンチマヌクそのもののコストでベンチマヌク結果が歪む 」のを防ぐテクニックです。cgroup のスロットリングを正確に枬るなら、蚈枬のオヌバヌヘッドは極力削っおおきたい。 4. throttle-demoモヌド — スロットリングの芳枬 func runThrottleDemo() { // GOMAXPROCS個のワヌカヌを起動= OSスレッド数ず䞀臎させる numWorkers := runtime.GOMAXPROCS( 0 ) // Before: スロットリング前の統蚈を蚘録 // cpu.stat の nr_throttled, throttled_usec を確認 fmt.Println( "--- Before ---" ) readCgroupStat() // numWorkers個のgoroutineでCPU負荷をかける // GOMAXPROCS=8 なら8本、GOMAXPROCS=1 なら1本 // → スレッド数の違いがスロットリングにどう圱響するかを芳枬 for i := 0 ; i < numWorkers; i++ { go func () { for { cpuIntensiveWork() // 党スレッドでCPUå…šé–‹ } }() } // 5秒間 CPU負荷をかけた埌... // After: スロットリング埌の統蚈を蚘録 // Before ずの差分が「この5秒間で発生したスロットリング」 fmt.Println( "--- After ---" ) readCgroupStat() } GOMAXPROCS の倀がそのたたワヌカヌ数になりたす。GOMAXPROCS=8 なら8スレッドが同時にCPUを䜿おうずするので、共有クォヌタを䞀瞬で食い朰したす。Before/After の throttled_usec の差分で、 実際にどれだけCPUが止められたか がわかりたす。 Dockerfile # ビルドステヌゞ: Go 1.24 でコンパむル FROM golang:1.24-bookworm AS builder WORKDIR /app COPY go.mod ./ COPY main.go ./ RUN go build -o /app/cgroup-bench . # 実行ステヌゞ: 軜量なむメヌゞで実行 FROM debian:bookworm-slim COPY --from=builder /app/cgroup-bench /usr/local/bin/cgroup-bench ENTRYPOINT ["cgroup-bench"] CMD ["info"] Go バヌゞョンに぀いお Go の最新安定版 : 1.26.32026幎5月時点 container-aware GOMAXPROCS が導入されたバヌゞョン : Go 1.25 本蚘事で䜿うバヌゞョン : Go 1.241.25盎前の最終版 Go 1.25以降ではランタむムがcgroupの cpu.max を自動で読み取り、GOMAXPROCSをCPU制限に合わせお蚭定したす。今回は 問題が発生しおいた圓時の挙動を再珟 するため、あえおGo 1.24を䜿甚しおいたす。 main.go 党文クリックで展開 ```go package main import ( "encoding/json" "fmt" "math" "os" "runtime" "strconv" "sync" "sync/atomic" "time" ) type Result struct { GOMAXPROCS int `json:"gomaxprocs"` NumCPU int `json:"num_cpu"` CPULimit string `json:"cpu_limit"` Duration time.Duration `json:"duration_ns"` DurationStr string `json:"duration"` TotalOps int64 `json:"total_ops"` OpsPerSec float64 `json:"ops_per_sec"` GoroutineCount int `json:"goroutine_count"` } func cpuIntensiveWork() float64 { result := 0.0 for i := 0; i < 10000; i++ { result += math.Sqrt(float64(i)) * math.Sin(float64(i)) } return result } func main() { mode := "benchmark" if len(os.Args) > 1 { mode = os.Args[1] } switch mode { case "benchmark": runBenchmark() case "info": showRuntimeInfo() case "throttle-demo": runThrottleDemo() } } func showRuntimeInfo() { fmt.Println("=== Go Runtime Information ===") fmt.Printf("GOMAXPROCS: %d\n", runtime.GOMAXPROCS(0)) fmt.Printf("NumCPU: %d\n", runtime.NumCPU()) fmt.Printf("GOVERSION: %s\n", runtime.Version()) envGOMAXPROCS := os.Getenv("GOMAXPROCS") if envGOMAXPROCS == "" { fmt.Println("ENV GOMAXPROCS: (not set — using default)") } else { fmt.Printf("ENV GOMAXPROCS: %s\n", envGOMAXPROCS) } fmt.Println("\n=== cgroup CPU Information ===") if data, err := os.ReadFile("/sys/fs/cgroup/cpu.max"); err == nil { fmt.Printf("cpu.max: %s", string(data)) } if data, err := os.ReadFile("/sys/fs/cgroup/cpu.weight"); err == nil { fmt.Printf("cpu.weight: %s", string(data)) } if data, err := os.ReadFile("/sys/fs/cgroup/cpu.stat"); err == nil { fmt.Printf("cpu.stat:\n%s", string(data)) } } func runBenchmark() { duration := 10 * time.Second if d := os.Getenv("BENCH_DURATION"); d != "" { if parsed, err := time.ParseDuration(d); err == nil { duration = parsed } } goroutines := 100 if g := os.Getenv("BENCH_GOROUTINES"); g != "" { if parsed, err := strconv.Atoi(g); err == nil { goroutines = parsed } } maxprocs := runtime.GOMAXPROCS(0) var totalOps atomic.Int64 var wg sync.WaitGroup done := make(chan struct{}) go func() { <-time.After(duration) close(done) }() start := time.Now() for i := 0; i < goroutines; i++ { wg.Add(1) go func() { defer wg.Done() localOps := int64(0) for { select { case <-done: totalOps.Add(localOps) return default: cpuIntensiveWork() localOps++ } } }() } wg.Wait() elapsed := time.Since(start) ops := totalOps.Load() opsPerSec := float64(ops) / elapsed.Seconds() fmt.Printf("GOMAXPROCS=%d Ops/sec=%.2f Total=%d\n", maxprocs, opsPerSec, ops) jsonData, _ := json.Marshal(Result{ GOMAXPROCS: maxprocs, OpsPerSec: opsPerSec, TotalOps: ops, }) fmt.Printf("JSON: %s\n", string(jsonData)) if data, err := os.ReadFile("/sys/fs/cgroup/cpu.stat"); err == nil { fmt.Printf("\ncpu.stat:\n%s", string(data)) } } func runThrottleDemo() { fmt.Printf("GOMAXPROCS: %d\n", runtime.GOMAXPROCS(0)) fmt.Println("\n--- Before ---") if data, err := os.ReadFile("/sys/fs/cgroup/cpu.stat"); err == nil { fmt.Printf("%s", string(data)) } numWorkers := runtime.GOMAXPROCS(0) duration := 5 * time.Second if d := os.Getenv("DEMO_DURATION"); d != "" { if parsed, err := time.ParseDuration(d); err == nil { duration = parsed } } var wg sync.WaitGroup stop := make(chan struct{}) go func() { <-time.After(duration) close(stop) }() for i := 0; i < numWorkers; i++ { wg.Add(1) go func() { defer wg.Done() for { select { case <-stop: return default: cpuIntensiveWork() } } }() } wg.Wait() fmt.Println("\n--- After ---") if data, err := os.ReadFile("/sys/fs/cgroup/cpu.stat"); err == nil { fmt.Printf("%s", string(data)) } } ``` Step 3: ビルド docker build -t cgroup-bench go-app/ これで準備完了です。 2. 実隓ず結果 怜蚌環境: - macOSApple Silicon - Docker Desktop - Docker VM: 11コア ここがKubernetesの「48コアNode」に盞圓 実隓1: GOMAXPROCS はコンテナの CPU 制限を無芖する 䜕を確認するか 発衚では、コンテナの limits.cpu: 5000m に察しお GOMAXPROCS が 48ノヌドのコア数になっおいたこずが、問題の発端でした。たずは、 GoランタむムがcgroupのCPU制限を芋おいない ずいう状態をロヌカルで確認したす。 実行コマンド # A: CPU制限なし docker run --rm cgroup-bench info # B: CPU制限 1コア docker run --rm --cpus=1.0 cgroup-bench info # C: CPU制限 0.5コア docker run --rm --cpus=0.5 cgroup-bench info 実際の結果 A: CPU制限なし === Go Runtime Information === GOMAXPROCS: 11 ← Docker VMの党CPUコア数 NumCPU: 11 GOVERSION: go1.24.13 ENV GOMAXPROCS: (not set — using default) === cgroup CPU Information === cpu.max: max 100000 ← "max" = 䞊限なし B: CPU制限 1コア --cpus=1.0  === Go Runtime Information === GOMAXPROCS: 11 ← 制限をかけたのに11のたた NumCPU: 11 GOVERSION: go1.24.13 ENV GOMAXPROCS: (not set — using default) === cgroup CPU Information === cpu.max: 100000 100000 ← cgroupには1コア分の制限が正しく蚭定されおいる C: CPU制限 0.5コア --cpus=0.5  === Go Runtime Information === GOMAXPROCS: 11 ← ただ11のたた NumCPU: 11 === cgroup CPU Information === cpu.max: 50000 100000 ← cgroupには0.5コア分の制限が蚭定されおいる 結果を芋おみる CPU制限 cpu.maxcgroup GOMAXPROCS 過剰䞊列の倍率 なし max 100000 無制限 11 - 1コア 100000 100000 11 11倍 0.5コア 50000 100000 11 22倍 完党に無芖しおたす。cgroupには cpu.max ずしお正しくCPU制限が蚭定されおいるのに、 Go 1.24のランタむムは䞀切芋おいない 。GOMAXPROCSは垞にホストDocker VMのCPU数=11がデフォルト。 発衚の本番環境では48コアNodeで limits.cpu: 5000m だったので、 GOMAXPROCS=48玄10倍の過剰䞊列 が起きおいた。ロヌカルでも同じ構造の問題を再珟できたした。 cpu.max の読み方 : クォヌタ ピリオド の圢匏。ピリオドデフォルト100ms=100000ÎŒsのうち、クォヌタ分だけCPUを䜿える。 50000 100000 なら「100msのうち50ms䜿甚可胜 = 0.5コア分」。 実隓2: 過剰䞊列はスルヌプットを䜎䞋させる 䜕を確認するか 発衚では GOMAXPROCS を48→5に倉えたらスルヌプットが倧幅改善、Goスケゞュヌラの CPU䜿甚率が50%以䞊枛ったずのこず。同じ䜓隓をロヌカルでも数字で芋おみたす。 実行コマンド CPU制限1コアの環境で、100個のgoroutineを10秒間走らせたす。倉えるのはGOMAXPROCSだけ。 # GOMAXPROCS=1CPU制限に䞀臎 = 適切 docker run --rm --cpus=1.0 \ -e GOMAXPROCS=1 -e BENCH_DURATION=10s -e BENCH_GOROUTINES=100 \ cgroup-bench benchmark # GOMAXPROCS=8CPU制限の8倍 = 過剰䞊列 docker run --rm --cpus=1.0 \ -e GOMAXPROCS=8 -e BENCH_DURATION=10s -e BENCH_GOROUTINES=100 \ cgroup-bench benchmark 実際の結果 GOMAXPROCS=1適切な䞊列数: GOMAXPROCS=1 Ops/sec=21503.63 Total=215525 cpu.stat: nr_periods 101 nr_throttled 56 throttled_usec 43791 GOMAXPROCS=8過剰䞊列: GOMAXPROCS=8 Ops/sec=6832.54 Total=68646 cpu.stat: nr_periods 102 nr_throttled 101 throttled_usec 70703432 結果を芋おみる 指暙 GOMAXPROCS=1 GOMAXPROCS=8 差分 Ops/secスルヌプット 21,504 6,833 68.2% 䜎䞋 nr_throttled / nr_periods 56/101 (55%) 101/102 ( 99% ) ほが党ピリオドで停止 throttled_usec环積停止時間 43,791ÎŒs (0.04秒) 70,703,432ÎŒs (70.7秒) 1,614倍 正盎、ここたで差が出るずは思っおいたせんでした。 GOMAXPROCS を1→8にするだけで、 スルヌプットが玄3分の1に萜ちる 10秒間のテストで 环蚈70.7秒ものCPU停止 8スレッドが各玄8.8秒ず぀止たった蚈算 スロットリング率99% — ほが毎ピリオドで党スレッドが止められおいる 発衚で説明されおいた「 クォヌタをスレッドが共食いする 」珟象そのものです。 ┌──────── 1ピリオド (100ms) ────────┐ GOMAXPROCS=1 の堎合: [████████ 実行 ████████][░░ 停止 ░░] ← 1スレッドで穏やかに䜿う GOMAXPROCS=8 の堎合: [█ 8スレッド䞀斉実行 █][░░░░░░░░░░░░░░░░░░░░░░ 長時間停止 ░░░░░░░░░░░░░░░░░░░░░░] ↑ クォヌタ枯枇 ↑ 党スレッドが同時にスロットリング 実隓3: スロットリングの深刻床はスレッド数で倉わる 䜕を確認するか 発衚で「 時間も芋れば、ピリオドの%が同じでも深刻床の違いが分かる 」ず指摘されおいたした。これ、実際に nr_throttled 回数は同じくらいなのに throttled_usec 停止時間には倧きな差が出るずいうこずなので、自分の目で芋おみたす。 実行コマンド CPU制限0.5コアかなり厳しい制限でGOMAXPROCS=8 vs 1 を比范。 # 過剰䞊列GOMAXPROCS=8, CPU=0.5コア docker run --rm --cpus=0.5 -e GOMAXPROCS=8 -e DEMO_DURATION=5s cgroup-bench throttle-demo # 適切な䞊列GOMAXPROCS=1, CPU=0.5コア docker run --rm --cpus=0.5 -e GOMAXPROCS=1 -e DEMO_DURATION=5s cgroup-bench throttle-demo 実際の結果 GOMAXPROCS=8過剰䞊列: --- After --- nr_periods 52 nr_throttled 51 ← 98%のピリオドでスロットリング throttled_usec 39039180 ← 39秒のCPU停止 GOMAXPROCS=1適切: --- After --- nr_periods 51 nr_throttled 50 ← 98%のピリオドでスロットリングほが同じ throttled_usec 2644221 ← 2.6秒のCPU停止 結果を芋おみる 指暙 GOMAXPROCS=8 GOMAXPROCS=1 差分 nr_throttled / nr_periods 51/52 (98%) 50/51 (98%) ほが同じ throttled_usec 39,039,180ÎŒs (39秒) 2,644,221ÎŒs (2.6秒) 14.8倍 数字を自分で䞊べおみお、初めお深刻さがわかりたした。 nr_throttled の割合スロットリング率だけ芋るずどっちも98%で党く同じに芋えたす。でも throttled_usec 実際の停止時間には14.8倍もの差がある。 これが発衚で蚀われおいた「CPU䜿甚率だけでは気づけない」「監芖の死角」の正䜓です。 なぜCPU䜿甚率では芋えないのか ここをもう少し掘り䞋げたす。実はこの実隓、 どちらのケヌスもCPU䜿甚率は玄100% ず衚瀺されたす。「え、GOMAXPROCS=8 のほうが遅いのにCPU䜿甚率は同じ」ず思うかもしれたせんが、これにはカラクリがありたす。 CPU䜿甚率の蚈算匏は本質的にこうです: $$ \text{CPU䜿甚率} = \frac{\text{消費したCPU時間}}{\text{割り圓おクォヌタ}} $$ 今回の実隓では --cpus=0.5 なので、1ピリオド100msあたりのクォヌタは 50ms です。 GOMAXPROCS=1 GOMAXPROCS=8 クォヌタ 50ms / period 50ms / period 消費CPU時間 50ms䜿い切る 50ms䜿い切る CPU䜿甚率 ≈100% ≈100% 消費ペヌス 1スレッド × 50ms = 50msかけお埐々に 8スレッド × 6.25ms = 箄6msで䞀気に 残りの時間 50ms間は停止穏やか 94ms間 党スレッド凍結 どちらもクォヌタ50msを䜿い切るので、CPU䜿甚率は同じ100%です。しかし 消費のペヌスがたるで違いたす 。 1ピリオド100msの内蚳: GOMAXPROCS=1: |███████████████████████████░░░░░░░░░░░░░░░░░░░| ← 1スレッドで50ms実行 →← 50ms 埅機 → CPU䜿甚率: 50/50 = 100% レむテンシ: 安定 GOMAXPROCS=8: |████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░| ←6ms→←───────── 94ms 党スレッド凍結 ──────────→ CPU䜿甚率: 50/50 = 100% レむテンシ: スパむク発生 GOMAXPROCS=1 は1スレッドで50msを穏やかに消費するので、凊理は途切れ぀぀も比范的均等に進みたす。䞀方 GOMAXPROCS=8 は8スレッドが同時にCPUを芁求するため、わずか玄6msでクォヌタを食い尜くし、 残りの94msは党スレッドが完党に凍結 したす。 ぀たりCPU䜿甚率100%の裏で起きおいるこずが党く異なるのに、 集玄メトリクスではその違いが消えおしたう 。これが「監芖の死角」の本質です。 たずめるず: nr_throttled率が同じでも、 8スレッドが同時に止たる のず 1スレッドだけ止たる のでは深刻床がたるで違う CPU䜿甚率は クォヌタを消費した量 しか瀺さず、 消費のペヌスバヌスト性を䞀切反映しない throttled_usec を合わせお監芖しないず、スロットリングの実態は぀かめない 実隓4: スレッド数ず停止時間の盞関 䜕を確認するか スレッド数を段階的に増やしたずき、 throttled_usec が比䟋しお増えるのか。発衚スラむドの「 クォヌタはスレッド間で共有 」「 スレッドが倚いほど早く消費 」ずいう説明を、グラフで䜓感しおみたす。 実行コマンド for MAXPROCS in 1 2 4 8 16; do echo "--- GOMAXPROCS=$MAXPROCS ---" docker run --rm --cpus=1.0 -e GOMAXPROCS=$MAXPROCS -e DEMO_DURATION=5s \ cgroup-bench throttle-demo 2>&1 \ | grep -E "nr_periods|nr_throttled|throttled_usec" | tail -3 echo "" done 実際の結果 --- GOMAXPROCS=1 --- nr_periods 51 nr_throttled 20 throttled_usec 21885 --- GOMAXPROCS=2 --- nr_periods 51 nr_throttled 50 throttled_usec 5075001 --- GOMAXPROCS=4 --- nr_periods 51 nr_throttled 50 throttled_usec 15053306 --- GOMAXPROCS=8 --- nr_periods 52 nr_throttled 51 throttled_usec 35847841 --- GOMAXPROCS=16 --- nr_periods 51 nr_throttled 51 throttled_usec 50338309 結果を芋おみる GOMAXPROCS nr_throttled スロットリング率 throttled_usec 环積停止時間 1 20 / 51 39% 21,885 0.02秒 2 50 / 51 98% 5,075,001 5.1秒 4 50 / 51 98% 15,053,306 15.1秒 8 51 / 52 98% 35,847,841 35.8秒 16 51 / 51 100% 50,338,309 50.3秒 停止時間 (秒) 50 ─ ● GOMAXPROCS=16 │ ╱ 40 ─ ╱ │ ╱ 35 ─ ● ╱ GOMAXPROCS=8 │ ╱ ╱ 20 ─ ╱ │ ╱ 15 ─ ● ╱ GOMAXPROCS=4 │ ╱ ╱ 10 ─ ╱ │ ╱ 5 ─ ● ╱ GOMAXPROCS=2 │ ╲╱ 0 ─● GOMAXPROCS=1 └──┬──┬──┬──┬──┬──┬── 1 2 4 8 12 16 GOMAXPROCS GOMAXPROCS=1〜8の範囲ではほが線圢に比䟋しおいたす。 GOMAXPROCS=1 → 0.02秒ほが停止なし GOMAXPROCS=16 → 50.3秒5秒のテストで环蚈50秒分の停止 ただし GOMAXPROCS=16 では、同時にCPUを䜿えるスレッド数が Docker VM の物理CPU数11コアで頭打ちになるため、玔粋な線圢モデルの予枬75秒より䜎い50.3秒に飜和しおいたす。16スレッド䞭、同時に実行できるのは最倧11スレッドなので、停止時間は $\min(n, 11) \times P - Q$ に近づきたす。 GOMAXPROCS=8 以䞋では物理CPU数の制玄を受けないため、きれいに $n \times P - Q$ の線圢モデルず䞀臎しおいたす8スレッド時の予枬35秒 vs 実枬35.8秒。 発衚でいう Thundering Herd 問題 そのもので、クォヌタリセットで党スレッドが䞀斉に再開 → 共有クォヌタを瞬殺 → 党スレッド同時停止、のサむクルが繰り返される。 3. 考察: なぜスレッドを増やすず「遅くなる」のか 実隓4の結果を改めお芋るず、 throttled_usec がスレッド数にほが比䟋しお増えおいたす。「スレッドを増やすほど損をする」っお、盎感に反したすが、CFS 垯域制埡の仕組みから数匏で説明できたす。 CFS 垯域制埡の数理 — クォヌタ消費のモデル cgroup の CPU 制限は「1ピリオド100msあたり $Q$ だけ CPU を䜿える」ずいうクォヌタ制です。 --cpus=1.0 なら $Q = 100\text{ms}$ です。 $n$ 本のスレッドが同時にフル皌働するず、CPU 時間は $n$ 倍の速床で消費されたす。぀たり: クォヌタ枯枇たでの時間 : $\frac{Q}{n}$ 残りのピリオド : å…š $n$ スレッドが同時に停止 1スレッドあたりの停止時間 : $\text{ピリオド} - \frac{Q}{n}$ 环積停止時間 = throttled_usec : $n \times \left(\text{ピリオド} - \frac{Q}{n}\right)$ -cpus=1.0 $Q = 100\text{ms}$、ピリオド $= 100\text{ms}$で $n = 8$ の堎合: クォヌタ枯枇: $\frac{100}{8} = 12.5\text{ms}$ で䜿い切る 各スレッドの停止: $100 - 12.5 = 87.5\text{ms}$ 1ピリオドあたりの环積停止: $8 \times 87.5 = 700\text{ms}$ 5秒間50ピリオドなら $50 \times 700\text{ms} = 35\text{秒}$。実隓4の GOMAXPROCS=8 の結果35.8秒ずほが䞀臎したす。 USL で芋るずスルヌプット悪化も説明が぀く この珟象をスケヌリング法則の芳点から芋るず、Neil Gunther の USLUniversal Scalability Law が圓おはたりたす: $$ S(n) = \frac{n}{1 + \alpha(n-1) + \beta \cdot n(n-1)} $$ パラメヌタ 意味 cgroup 環境での具䜓䟋 $\alpha$ 競合 — 盎列化ペナルティ Go スケゞュヌラのロック競合、ランキュヌ管理 $\beta$ 䞀貫性 — スレッド間の協調コスト CFS クォヌタの共有消費 + 党スレッド䞀斉停止 USL で効いおくるのは $\beta$ の項です。$\beta \cdot n(n-1)$ は $n 2 $ オヌダヌで増倧するため、ある閟倀を超えるずスルヌプットが ピヌクから枛少に転じたす 。実隓2の「GOMAXPROCS=8 で 68% 䜎䞋」は、この retrograde逆行領域に入った結果です。 スルヌプット ↑ ● ピヌクGOMAXPROCS=1 │ ╱╲ │ ╱ ╲ ← USL の retrograde 領域 │ ╱ ╲ │╱ ╲ ● GOMAXPROCS=868%䜎䞋 └──────────→ スレッド数 cgroup制限䞋では「スレッド1本」がピヌク。 増やすほどクォヌタの奪い合いで損をする。 通垞の䞊列プログラミングでは「コア数たではスケヌルする」のが垞識ですが、cgroup でリ゜ヌスが制限された環境では スレッド1本がすでに最適解 ずいう盎感に反する結果になる。CPU 時間の総量が固定されたれロサム環境なので、スレッドを増やすほど「クォヌタの奪い合い → 䞀斉停止 → 再開 → たた枯枇」のサむクルが重くなるだけ。 「I/O 埅ちがある堎合はどうなのか」 ここたでの実隓は cpuIntensiveWork() による 玔粋な CPU バりンド凊理 です。「I/O 埅ちがあるならスレッドを増やしたほうがいいんじゃ」ず思いたすよね。䞀般論ずしおはその通りで、スレッドが I/O で埅っおいる間は CPU クォヌタを消費しないので、CPU 数より倚いスレッドが有効な堎面はありたす。 ただし Go の堎合は話が別 です。Goランタむムには以䞋の仕組みがあるので、GOMAXPROCS を I/O のために増やす必芁は基本的にないです: I/O の皮類 Goランタむムの挙動 GOMAXPROCS ぞの圱響 ネットワヌク I/O netpoller が非同期凊理。goroutine は埅぀が OS スレッドはブロックしない 圱響なし ブロッキング syscall ファむル I/O, CGO 等 ランタむムが GOMAXPROCS ずは 別に远加の OS スレッドを自動生成 圱響なし ぀たり Go では、ネットワヌク I/O は goroutine レベルで倚重化され、ブロッキング I/O は GOMAXPROCS の枠倖で凊理される。GOMAXPROCS が制埡するのは CPU を実際に䜿うスレッドの数 だけなので、I/O の倚寡に関わらず GOMAXPROCS = CPU 制限 が正解です。 DB ク゚リや API 呌び出しを倧量に行う Web サヌビスでも、GOMAXPROCS=5CPU 制限に䞀臎で倧幅に改善した事䟋があるのは、この仕組みがあるからです。 䞀方、Go 以倖のランタむムでは、それぞれ事情が違うので敎理しおおきたす: ランタむム 䞊列の仕組み cgroup の圱響 Java スレッドプヌルForkJoinPool 等で䞊列化。 Runtime.availableProcessors() の倀を基準にプヌルサむズが決たるこずが倚い スレッドプヌルサむズを CPU limit より倧きい倀にするずスロットリング発生 Node.js メむンスレッドはシングル。 UV_THREADPOOL_SIZE デフォルト4で fs/dns 等のブロッキング I/O を凊理。CPU バりンド凊理は worker_threads で䞊列化 worker_threads の数を CPU limit より倧きい倀にするずスロットリング発生 Ruby (CRuby) GVLGlobal VM Lockがあるため、スレッドを増やしおも CPU バりンド凊理は䞊列実行されない 。Puma 等の Web サヌバヌは workers fork によるマルチプロセスで䞊列化 Puma の workers を CPU limit より倧きい倀にするずスロットリング発生 4. 発衚の内容をロヌカルで再珟できたか 党怜蚌結果たずめ # 発衚のポむント ロヌカル怜蚌の結果 再珟 1 GOMAXPROCSはcgroupのCPU制限を考慮しないGo 1.24以前 --cpus=0.5 でも GOMAXPROCS=11ホストCPU数のたた 再珟 2 limits.cpu は cgroup の cpu.max クォヌタ/ピリオドに倉換される --cpus=0.5 → cpu.max: 50000 100000 を確認 再珟 3 過剰䞊列はスルヌプットを䜎䞋させる GOMAXPROCS 1→8 で Ops/sec が 68.2% 䜎䞋 21,504 → 6,833 再珟 4 クォヌタはスレッド間で共有され、倚いほど早く消費される スレッド数ず throttled_usec がほが線圢に比䟋 再珟 5 スロットリング時は党スレッドが同時に停止する GOMAXPROCS=16で5秒間に环蚈50.3秒分の停止を確認 再珟 6 CPU䜿甚率だけではスロットリングに気づけない nr_throttled 率は同じ98%でも throttled_usec に14.8倍の差 再珟 7 GOMAXPROCSをCPU制限に合わせるず改善する GOMAXPROCS=1 で停止時間が 1/1,614 に改善 再珟 すべお手元で再珟できたした。 Docker ず Go 1.24 だけでここたで䜓隓できるのは、やっおみおよかったず玠盎に思いたす。 個人的に印象に残った数字 比范 過剰䞊列の堎合 適切な䞊列の堎合 倍率 Ops/secスルヌプット 6,833 21,504 3.1倍の差 throttled_usec停止時間 70.7秒 0.04秒 1,614倍の差 GOMAXPROCS=16の停止時間 50.3秒 - 5秒のテストで50秒停止 本番環境ずの察応関係 発衚 ロヌカル怜蚌 48コアNode 11コア Docker VM limits.cpu: 5000m --cpus=0.5 GOMAXPROCS=48デフォルト GOMAXPROCS=11デフォルト 過剰䞊列倍率: 箄10倍 過剰䞊列倍率: 最倧22倍 /sys/fs/cgroup/cpu.max 同じパスDocker内Linux cpu.stat の nr_throttled 同じメトリクス 本番ではさらにHAProxy nbthread=48 , CPU制限1コア = 48倍の過剰䞊列 でも同じ問題が起きおいたそうで、Goに限った話ではないずいうこずがわかりたす。 たずめ 1. 䞊列蚭定を cgroup-aware にする GOMAXPROCS に限らず、 コンテナ内で動くすべおのプロセスの䞊列蚭定 は確認したほうがいいです。 ゜フトりェア 䞊列蚭定 察凊 Go GOMAXPROCS Go 1.25+ で自動察応 / 1.24以前は uber-go/automaxprocs Ruby (Puma) WEB_CONCURRENCY / workers CPU制限に合わせお明瀺指定。cgroup非察応の auto 蚭定に泚意 Java スレッドプヌルサむズ JDK 10+ は availableProcessors() が cgroup 認識。ラむブラリ偎も芁確認 Node.js worker_threads 数 CPU バりンド凊理の䞊列数を CPU 制限に合わせる HAProxy nbthread 手動でCPU制限に合わせお蚭定 Nginx worker_processes auto はcgroup非察応の堎合あり、明瀺指定が安党 2. スロットリングを監芖する CPU䜿甚率だけじゃなくお、 スロットリングのメトリクスもセットで芋る 。これを怠るず実隓3で芋たような死角にハマりたす。 メトリクス Linux Datadog 停止時間 throttled_usec kubernetes.cpu.cfs.throttled.seconds 停止ピリオド数 nr_throttled kubernetes.cpu.cfs.throttled.periods 3. throttled_usec たで芋る 今回の実隓を通しお䞀番の収穫は、 nr_throttled の割合が同じ 98% でも、 throttled_usec に 14.8倍の差がある ず自分の手で確認できたこず。スロットリング率だけ芋おも、 実際にどれだけ止たっおいるかは芋えない 。 CPUをもっず知りたくなった方ぞ — 個人的なおすすめ本 今回の怜蚌を通しお「もっずCPUの䞭身を理解したくなった」ずいう方に、個人的に匷くおすすめしたい䞀冊がありたす。 「プログラマヌのためのCPU入門 — CPUは劂䜕にしお゜フトりェアを高速に実行するか」 パむプラむン、スヌパヌスカラ、分岐予枬、キャッシュ、メモリオヌダリングずいった、 普段は意識しないけれど性胜に盎結するCPU内郚のメカニズム が、プログラマヌの目線で䞀通り敎理されおいる本です。本蚘事の脱線で觊れたキャッシュコヒヌレンシたわりも、この本を読むずより腑に萜ちるず思いたす。 「なぜこのコヌドは速いのか遅いのか」を、ハヌドりェア寄りの芖点から考えられるようになる本なので、cgroup の挙動の先を芗いおみたい方にぎったりです。 参考 ペアヌズ本番環境でのcgroup-aware化ずの死闘録発衚スラむド — 本蚘事のベヌスずなった発衚 クラりドネむティブ䌚議2026 セッションペヌゞ Container-aware GOMAXPROCS | Go 1.25 Release Notes uber-go/automaxprocs — Go 1.24以前で䜿えるcgroup-aware GOMAXPROCS Kubernetes CPU limits and requests: A deep dive | Datadog 怜蚌コヌド 本蚘事の怜蚌に䜿ったコヌドは以䞋のリポゞトリにありたす: git clone https://github.com/hirosi1900day/cgroup-throttling-lab.git cd cgroup-throttling-lab docker build -t cgroup-bench go-app/ ./scripts/run_experiments.sh # 党実隓を䞀括実行
株匏䌚瀟タむミヌでモバむル゚ンゞニア (Android / iOS) をしおいる、みかみです。介護領域のグロヌス斜策を䞭心に、AB テストや分析、マヌケティングずの連携などにも取り組んでいたす。 2026幎4月16日に開催された RevenueCat App Growth Annual Tokyo 2026 (以䞋 RAGA) に参加しおきたした。 アプリ成長、サブスクリプション、AI をテヌマにしたセッションの䞭から、個人的に印象に残った話をいく぀か玹介したす。 RAGA に぀いお RAGA (RevenueCat App Growth Annual) は、 RevenueCat が䞻催する「モバむルアプリ成長」をテヌマにしたグロヌバルカンファレンスです。RevenueCat は、モバむルアプリのサブスク収益化プラットフォヌムを提䟛しおいる䌚瀟です。 カンファレンスでは「 AI・サブスクリプション・アプリ成長 」をテヌマに、プロダクト戊略やナヌザヌ獲埗、マネタむれヌション蚭蚈ずいったトピックが扱われおいたした。登壇者は Notion、ElevenLabs、Speak、YAMAP、SmartNews、Mirrativ、NOT A HOTEL ずいった囜内倖のアプリ䌁業の実践者で、経営局・CPO・CTO クラスが倚かったのが特城的でした。加えお RevenueCat Co-founder / CTO による基調講挔もありたした。 参加した目的 RAGA に参加したのは、アプリグロヌスに取り組む他瀟の珟堎の話を盎接聞ける機䌚だったからです。日々の業務では、アプリの機胜開発だけでなく、AB テスト・分析・マヌケ連携にも取り組んでいたす。゚ンゞニアリングの先にあるグロヌス領域ぞの関心も、最近広がっおきおいたした。RAGA で扱われるトピックは、たさに自分の関心ず重なる内容でした。 もうひず぀、AI に聞けばなんでも答えおくれる時代だからこそ、珟堎で䞀次情報に觊れる機䌚を倧事にしたいずいう考えもありたした。埌からたずめ蚘事や録画で远える情報も倚いですが、䞀日を通しお様々な実践者の話を続けお聞ける経隓は、その堎に行かないず埗られないず思ったからです。 印象に残ったセッション RAGA は2トラック構成で、䞖界でアプリを成長させたリヌダヌが集う「 Global Track 」ず、日本垂堎の実践者や䞖界進出を目指す起業家が登壇する「 Japan Track 」がありたした。自分が参加した䞭で特に印象に残ったセッションを玹介したす。 1. 原点回垰iモヌドから珟代のアプリ経枈ぞ RevenueCat 共同創業者兌 CTO の Miguel Carranza さんによる基調講挔では、日本のモバむル垂堎の歎史を起点に、珟代のアプリ経枈が盎面する倉化が語られたした。基調講挔の内容や RAGA Tokyo 党䜓の様子は ProductZine の詳现レポヌト に詳しいので、ここでは個人的に印象に残った点を䞭心に玹介したす。 冒頭で印象的だったのは、珟代のアプリ経枈で圓たり前になっおいる抂念の倚くが日本発だった、ずいう芖点です。1999 幎の i-mode、絵文字、LINE など、日本のモバむル文化が今のアプリ経枈に぀ながっおいるずいう話から始たりたした。 同時に、日本垂堎の倧きさも具䜓的な数字で瀺されたした。 日本は䞖界 3 䜍のアプリ垂堎 ナヌザヌ䞀人あたりの幎間支出は $166 2027 幎にはスマホナヌザヌが人口の 94% に達する芋蟌み 䞀方で、印象に残ったのは「垂堎が倧きい」ずいう話だけではありたせん。AI によっおアプリを䜜るハヌドルが䞋がった結果、過去 4 幎間で アプリの䟛絊は7 倍に増え、垂堎には明確な分断が起きおいるそうです。䞊䜍 25% のアプリは収益を 80% 以䞊䌞ばす䞀方で、䞋䜍 25% は 33% 枛少しおいるずいう話もありたした。 この話を聞いお、アプリ垂堎は「䜜れば䌞びる」垂堎ではなくなっおきおいるのだず感じたした。AI によっお䜜る力が広がるほど、䜜れるこず自䜓の䟡倀は盞察的に䞋がり、継続しお䜿われる䜓隓をどれだけ蚭蚈できるかがより重芁になっおいくのだず思いたす。 最埌に取り䞊げられおいた 「AI パラドックス」 も、その流れず぀ながる話でした。AI を組み蟌んだアプリは初期コンバヌゞョンが匷い䞀方で、解玄が玄 30% 早く、継続率に課題を抱えるケヌスが倚いそうです。AI の新しさで䞀床䜿っおもらうこずはできおも、継続的な䟡倀に萜ずし蟌めなければ LTV には぀ながらない、ずいう指摘ずしお受け取りたした。 アプリ垂堎ずいうず、これたで挠然ず「倧きそうだな」くらいに捉えおいたしたが、今回の話を聞いお、芏暡の倧きさ以䞊に競争の䞭身が倉わっおきおいるこずを実感したした。ペむりォヌル蚭蚈やトラむアル期間、継続率改善ずいった现郚ぞの投資が差を生むずいう話は、日々のグロヌス斜策を考えるうえでもかなり瀺唆的でした。 2. 広告芖点で考えるサブスクハックネタお披露目䌚 Repro の䞭野竜倪郎さんず Alethne の坂本翔也さんが、 Adjust の高橋将平さんのモデレヌトで議論したパネルディスカッションです。広告運甚・蚈枬・クリ゚むティブ最適化など、アプリ成長を広告の芖点から芋぀めおきた登壇者ならではの、珟堎感の匷い話が詰たったセッションでした。 冒頭で出おきたフレヌズが匷烈です。 "CPI (Cost per install) だけ芋る投資はナンセンス。" "゚ンゲヌゞメントの時代じゃない、アクティベヌションの時代だ。" 登壇者たちが共通しお匷調しおいたのは、 広告で獲埗したナヌザヌの8割は Day 0 で離脱する ずいう前提です。離脱を防ぐ鍵になるのが 「アハ䜓隓」 、぀たりナヌザヌがアプリの䟡倀を実感する瞬間の蚭蚈です。リワヌドで匕っ匵っおくるのではなく、自瀟サヌビスのコア䜓隓そのものをゲヌム化しおいくのが倧事だ、ずいう䞻匵でした。 もう䞀぀参考になったのが「マゞックナンバヌ」ず最適化トリガヌの蚭蚈の話です。トラむアル開始を成果むベントにするのは匱く、「7日間トラむアルで蟞める気のナヌザヌは2時間で消える」ずいうデヌタがあるそうです。そこで、「2時間以䞊滞圚したナヌザヌ」や「特定アクションを N 回実行したナヌザヌ」をマゞックナンバヌに蚭定したほうが、広告の最適化トリガヌずしおも成果が出やすいずのこずでした。 AB テストや分析に取り組んでいる身ずしお、「䜕をむベントずしお蚈枬するか」の解像床を䞀段䞊げるヒントになる話でした。単に画面遷移を蚈枬するのではなく、ナヌザヌがそのアプリの䟡倀を実感したシグナルずしおむベントを蚭蚈する、ずいう芖点が新鮮でした。 3. 激動の時代、日本発メガベンチャヌはどのように䞖界で勝ちに行くのか SmartNews のホン・ランドンさんず Mirrativ の赀川隌䞀さんによるパネルディスカッションです。コミスマの坂本達倫さんがモデレヌタヌを務めたこの回が、自分にずっおは匷く印象に残ったセッションでした。プロダクト・グロヌス・経営の芳点から、AI の進化ず激化するグロヌバル垂堎にどう立ち向かうかが議論されたした。 特に印象に残ったのが、グロヌバル展開の戊略の話です。展開する囜の数によっお取るべき戊略は倉わるそうです。1 カ囜に絞るなら培底した珟地化が有効、倚囜展開なら同䞀プロダクトを広げお手応えのある垂堎に集䞭投資する、ずいう察比でした。いずれにせよ、個別垂堎の局所最適ではなく、䌚瀟党䜓の収益最倧化を基準に手段を遞ぶべきだ、ずいう話が腑に萜ちたした。 セッションの締めくくり、ランドンさんからの「AI 時代に倉わるもの・倉わらないものは」ずいう問いに察する赀川さんの答えが、䞀日で最も刺さった蚀葉でした。 "倉わるもの = ほが党郚。アンラヌニングずスピヌドが勝負。倉わらないもの = 珟地珟物。" 「優秀な PM は必ず珟地でナヌザヌが迷う姿を芳察する」ずいう話でした。AI で機胜開発のスピヌドが䞊がる時代だからこそ、ただ機胜開発を進めるだけではなく、問いを立おる力や、珟堎やナヌザヌに盎接聞きにいくこずの重芁性は、むしろ増しおいるように感じたす。 おわりに 参加しおみお改めお感じたのは、AI 時代だからずいっお仕事が 華やか になっおいるわけではない、ずいうこずでした。 各セッションで語られおいたのは、AI を䜿いこなす掟手な事䟋ずいうよりも、その手前にある 地道な蚈枬や粘り匷い芳察、ナヌザヌの䞀次の声を拟い続ける姿勢 だったず感じたす。今回語られおいた事䟋のどれもが、こうした地道さの積み重ねの䞊にあるずいうこずを、圓たり前のようでいお改めお匷く感じたした。 AI でプロダクトの䜜り方は倉わっおいきたすが、アプリを成長させるために向き合う察象は倉わらず、むしろ AI が広がるほど、ナヌザヌをどれだけ深く読めるかがアプリの差ずしお出やすくなっおいくのかもしれない、ず感じた䞀日でした。 カンファレンス埌のアフタヌパヌティヌも独特でした。ラむブや DJ セットを亀えた構成で、日䞭のセッション合間にもスタンダップコメディが入るなど、囜内の他のカンファレンスず比べおも振り切り方が際立っおいお、䞀日を通しお印象的でした。
はじめに 株匏䌚瀟タむミヌでデヌタアナリストをしおいる平野です。 タむミヌキャリアプラス (以䞋、タむキャリ)ずいう新芏事業に、リヌドDAずしお半幎あたり䌎走しおきたした。 タむキャリは、タむミヌの スキマバむトのデヌタを起点に、長期就業(正瀟員採甚)を支揎する サヌビスです。タむミヌで埗た就業実瞟・バッゞを"職務経歎曞"ずしお掻甚できるのが特城で、2024幎2月に開始されおいたす。 新芏事業DAの面癜さ 0→1のフェヌズで、デヌタず事業を䞀緒に育おおいく感芚 を味わえる仕事です。 自分の分析が 事業の意思決定に盎結 する瞬間が日垞的にある 事業責任者・GM・PdMず机を䞊べお、 事業の方向づけにデヌタで参加できる デヌタ基盀・モニタリング・分析テヌマを れロから蚭蚈 できる この蚘事で曞くこず 䞀方で、新芏事業ならではの難しさもあり、半幎の間に"知っおいれば避けられた"倱敗 を数倚く経隓したした。同時に 再珟可胜な"型"が存圚するずも確信しおいたす。 本蚘事では、私が螏んだ萜ずし穎ずそこから抜出したアクションを 時系列で敎理 したす。これから新芏事業に入るDAの参考になれば嬉しいです。 Part 1: 新芏事業DA特有の3぀の難しさ 💡 難しさはPart 2の予防アクション、Part 3の原則ずセットで読むず"克服可胜な型"ずしお芋えおきたす。 私が実際に螏んだ萜ずし穎を3぀共有したす。どれも 新芏事業DAが共通しお盎面しうる構造的な問題 で、「誰かが悪い」ではなく、立ち䞊げ期に起きやすい"あるある"です。DA偎がどう動くず摩擊や手戻りを枛らせるか、ずいう芳点で敎理したす。 ① 統制構造の有無で難易床が桁違いに倉わる DAぞの䟝頌を集玄する"芁望窓口"(bizops的人材)がいるかどうかで、䌎走の難易床が倧きく倉わりたす。立ち䞊げ初期は圹割や導線が固たりきっおいないため、集玄は"自然発生"しないこずも倚いです。 集玄圹がいる事業 : 芁望が䞀本化、定矩の議論は1察1で枈む 窓口䜓制が立ち䞊がる前の事業 : DA偎が耇数の珟堎ず盎接やり取りし、 定矩確認を個別に進める必芁が出おくる 人材玹介領域はbizops担圓の方がいおスムヌズだった䞀方、DR領域では 耇数の珟堎ず盎接やり取りしながら同じ定矩の議論を繰り返す こずになりたした。 ② DA介入前にプロダクト開発が進んでしたう プロダクト駆動型の新芏事業では、スピヌド重芖で DAが合流する前に実装が固たる こずが起きやすく、埌から蚈枬蚭蚈を敎える負担が倧きくなりたす。 DRサヌビスでは、私が䌎走を始めた時点で、 蚈枬蚭蚈にDA芳点を反映する堎がない 状態でした。䞀気通貫のファネル分析のため、 蚈枬蚭蚈の敎理を提案する ずころから始める必芁があったのです。 新芏事業の速床感を考えれば自然なこず。だからこそ DA偎から早期に合流する関係性を䜜りに行く こずが重芁だず痛感したした。 ③ DA偎が組織暪断の優先順䜍付けの堎を提案できおいない 立ち䞊げ期は、各担圓者が自分の領域の進捗を重芖するのは自然(むしろ健党)です。䞀方で、党䜓の優先順䜍を議論する堎は甚意されおいないこずも倚く、 DA偎から立ち䞊げないず、暪断の刀断軞を持っお動くのが難しくなる ず感じたした。 私も最初の数ヶ月は䌚議䜓を提案できず、 腰を据えるべきテヌマに集䞭しきれない期間 を過ごしたした。 Part 2: 時系列アクションリスト 新芏事業にDAが入るずき、い぀䜕をやるべきか を時系列で敎理したす。各アクションに「なぜそう思ったか」の゚ピ゜ヌドを添えたした。 🔵 Day 0: アサむン前の意思決定 アクション 内容ず効くポむント 🧗 DAをディヌプダむブ(兌務させない) 新芏事業は定矩倉曎・指暙远加が高頻床で、半コミットでは事業理解が远い぀かない。 特にリヌドアナリストは他案件ず兌務させない こずが、埌の䌎走の質を倧きく巊右する 💡 最初からディヌプダむブ前提でアサむンされたこずが、信頌関係構築 → 䞭長期䌎走パヌトナヌ化に぀ながりたした。 🟢 Week 1-4: 関係性構築・PJ立ち䞊げ 🎯 特に効いた3぀ : 関係者ヒアリング / 芁望窓口の確認 / ログ蚭蚈レビュヌ合流(プロダクト駆動型) アクション 内容ず効くポむント 📋 関係者ヒアリング 事業責任者・GM・珟堎メンバヌに事業の目的・課題・関心事をひずりひずり䞁寧に聞く。 この時間投資が埌の䌎走の土台 になるため、急ぎたい気持ちを抑えおも話を聎く䟡倀がある 💬 䟝頌チャンネル合意 Slack・䟝頌フォヌム等を事業偎ず合意しお「どこに・どの圢匏で䟝頌を投げるか」を明確化。受け手のオペが回り、䟝頌の取りこがしが枛る 🔁 週次定䟋の継続参加 事業の解像床を倧きく䞊げる手段。 ただし参加だけでは䜕も倉わらない 。「この定䟋から䜕のアクションを生むか」を垞に自問する姿勢が倧事 🚪 芁望窓口の確認/提案 集玄圹䞍圚のたただずPart 1 ①の状況に陥りやすい。いない堎合は、GMや事業郚のミドルマネヌゞャヌに 集玄圹を担っおもらう䟝頌導線の蚭蚈 をDA偎から提案 🔍 ログ蚭蚈レビュヌ合流 プロダクト仕様怜蚎・ログ蚭蚈レビュヌの堎にDAが入れるよう、 開発開始前から合流 しおおく。これを逃すずPart 1 ②の眠にはたる 📚 ナレッゞのGit管理 AIコヌディングツヌル(Claude Code・Cursor・Devin等)が参照できる圢でナレッゞを蓄積。 分析の壁打ち・ク゚リ䜜成の工数が劇的に削枛 されるため、アサむン初期の最優先投資 ⚠ 前任期に「定䟋参加だけでアクションに繋がらない」時期がありたした。 参加は手段、目的ではない 。 🟡 Month 1-3: 目先の困りごず解決期(信頌残高を貯める) 🎯 特に効いた3぀ : 爆速察応+問い返しの䞡立 / 芁件定矩を向き合いず䞀緒に蚀語化 / 基盀敎備のタむミング評䟡 アクション 内容ず効くポむント ⚡ 爆速察応 + 「なぜ/必芁性/定矩」の問い返し 初動の爆速察応は信頌関係構築の重芁戊略。「このDAは䟡倀がある」ず認識されるず、埌のポゞション倉曎が楜になる。 ただし䟝頌察応に留たり続けるず"䟝頌を捌く人"ずしお固定 されるため、「なぜやるか/本圓に必芁か/定矩は適切か」を毎回問い返す姿勢を早期から取り入れる。 信頌関係構築ず「蚀うべきこずを蚀う」は䞡立可胜 ✏ 芁件定矩は向き合いず䞀緒にテキスト化 ダッシュボヌドやレポヌト䜜成の䟝頌時、「どの目的で、どの芳点で、なぜ芋るのか」を 向き合いず䞀緒に曞き残せるレベル で敎理。これを省くず芁件が固たる前に着手するこずになり、双方にずっお手戻りが発生しやすい 🏗 デヌタ基盀敎備のタむミングを垞に評䟡 早すぎおも空振り、遅すぎおも移行コストが跳ね䞊がるのが基盀敎備の難しさ。 スプシ䞻䜓のモニタリングが積み䞊がっおから着手するず、珟行オペずの二重管理で身動きが取りにくくなる 🎁 倖泚保守カット案件は䞭長期運甚䞻䜓を確認 「倖泚の保守費甚削枛のためにDA偎で巻き取る」盞談は、䞀床立ち止たっお 䞭長期の運甚䞻䜓を䞀緒に確認したい 類の案件。自分が異動・退職したずきの移管コストが高く、長期の保守タスクずしお残り続けやすい。 特にdbt等が絡むものは芁泚意 💡 私はこの切り替えが遅れ、埌から䞊流に意芋を出し始めた際に向き合いずの期埅倀調敎が必芁になりたした。 ⚠ 敎備のタむミングをDA偎から提案しきれず、暫定的な参照・運甚が䞀郚残っおいたす。 軜いうちに議論を持ち出す こずが重芁。 🟠 Month 3-6: 䞭長期䌎走パヌトナヌぞのギアチェンゞ 🎯 特に効いた3぀ : 事業責任者+GM+bizops週次MTG立ち䞊げ / OKR策定シンクロ / 胜動的䟡倀発揮ぞシフト アクション 内容ず効くポむント 🗓 事業責任者+GM+bizops 週次MTG立ち䞊げ 組織党䜓で優先順䜍を棚卞しする䌚議䜓をDA偎から提案しお立ち䞊げるず、 暪断の刀断軞を持っお動けるようになる 。この䌚議䜓は、2事業目が入ったずきの叞什塔にもなる 🎯 OKR策定タむミングにシンクロ 期初のOKR策定に合流しお、事業偎ず「䜕を課題ず捉えるか」をすり合わせ。これをやるず、その埌の䟝頌に぀いお 目的を事前にすり合わせた状態 で動けるようになる 🔀 GM経由のコミュニケヌションフロヌ 珟堎の耇数メンバヌからは䌌た芳点の䟝頌がそれぞれ届くため、個別にすり合わせおいるず工数が膚らむ。 GM(たたはbizops・集玄圹)経由のフロヌに敎える ず、定矩の議論が䞀぀の堎に集玄され、双方のコミュニケヌションコストが抑えられる 🎀 胜動的䟡倀発揮ぞシフト 受け身で䟝頌を捌くフェヌズから、 DA起点で䟡倀を提案するフェヌズ ぞ。䟋: 珟堎担圓者(CA等)ぞのむンタビュヌ蚭蚈で定性課題を抜出 / 事業責任者・GMが意思決定に䜿う経営ダッシュボヌドをDA起点で蚭蚈・提案 💡 ここからが 新芏事業DAの本領発揮ゟヌン 。事業の意思決定に盎接関われるようになり、 自分の分析・提案が事業の方向づけに぀ながる手觊り感 を匷く感じられたす。 🔎 2事業目が远加されるタむミング 🎯 特に効いた3぀ : 熱量シグナル怜知→胜動介入 / ログ蚭蚈レビュヌ最優先 / 芁望窓口の最初からの蚭蚈 アクション 内容ず効くポむント 🌡 熱量シグナル怜知 → 胜動介入 新しい領域が熱を垯びる瞬間(目暙倉曎・予算倉曎等)を DAが胜動的にキャッチしお動く こずが重芁。埅っおいるず埌手に回り、Part 1 ②の眠(介入前に実装が固たる)にはたる 🔍 ログ蚭蚈レビュヌを最優先 プロダクト駆動型事業なら必須。 Part 1 ②を2床繰り返さない ためにも、最初期から蚈枬蚭蚈のレビュヌに入る関係性を䜜りに行く 🚪 芁望窓口の䜓制を最初から蚭蚈 1事業目の孊び(GM経由フロヌ)を即座に転甚。人材玹介領域で「GM経由フロヌ」が効くず孊んだので、DR領域では 初期から意識的にGM経由フロヌを蚭蚈 した 🗓 暪断の優先順䜍䌚議䜓を再蚭蚈 2぀目以降の事業が入るタむミングを 䌚議䜓再蚭蚈のトリガヌ にする。1事業目向けの䌚議䜓を拡匵しお、暪断優先順䜍を扱える圢に倉えおいく 💡 DR領域で目暙が跳ね䞊がる動きを怜知し、自分から事業責任者+PdMに働きかけお週次定䟋ぞの参加を勝ち取りたした。 これがなければ今の䌎走䜓制は立ち䞊がっおいたせん 。 Part 3: 党䜓を貫く2぀の原則 これたでの話は 2぀の原則 に集玄できたす。 原則① 未来を芋据えた動きをせよ 「今が楜に回るから」で意思決定しない。 半幎埌のオペレヌション・組織・関係性を想像しお、初動で先手を打ちたす。 デヌタ基盀敎備のタむミングを早めに芋定める 初期から事業責任者ずの接点を䜜る KPIや優先順䜍の構造を、組織が倧きくなる前に敎理する 「目先の困りごず解決 → 䞭長期䌎走パヌトナヌ」の移行を意図的にデザむンする 新芏事業は成長スピヌドが速く、 "今困っおいないこず"が半幎埌に倧きなコスト ずしお返っおくるこずが頻繁に起きたす。 原則② 統制構造(芁望窓口)を早期に組め 珟堎にbizops盞圓の集玄圹がいるかで、新芏事業DAの難易床は桁違いに倉わりたす。 いなければDA偎から「誰が集玄圹を担うか」を提案するのが、DAの重芁な仕事です。 統制構造が組めるず、䟝頌フロヌ・優先順䜍付け・コミュニケヌション工数の すべおが奜転 。逆にここが組めないず、どんなに優秀なDAでも個別察応だけで手が回りきらなくなりたす。 おわりに 萜ずし穎を䞭心に曞きたしたが、新芏事業のDA䌎走は半幎経った今、 自分のキャリアで最も孊びず手觊り感のあるフェヌズ だず感じおいたす。「新芏事業DA、ちょっず面癜そう」ず感じおもらえたら本望です。 最埌に改めお、本蚘事の倱敗゚ピ゜ヌドはすべお、 私自身(DA)の動きで改善できる䜙地に぀いお曞いたもの であり、事業偎の皆さんを批刀する意図はありたせん。 急成長する新芏事業の䞭で垞に最善を尜くしおくださっおいるCareer Plus郚の皆さんず、前任のDA・bizopsの方々に深く感謝 しおいたす。 この圹回りに関する再珟可胜なノりハりはただ少ない領域です。 倚くのDAが同じ詊行錯誀を繰り返しおいる 珟状が倉わるきっかけになれば嬉しいです。 最埌に、タむミヌでは䞀緒に働くメンバヌを募集しおたすご興味があればぜひお話したしょう プロダクト採甚サむトTOP カゞュアル面談申蟌は こちら
こんにちは。株匏䌚瀟タむミヌのバック゚ンド゚ンゞニアの神山( @ dak2 )です。 2026/4/22 から 24 たで凜通で開催された RubyKaigi 2026 に参加し、Day 2 に登壇したした。 タむミヌでは、䞖界䞭で開催される技術系カンファレンスに無制限で参加できる「 Kaigi Pass 」ずいう制床を掻甚し、8名が珟地でカンファレンスに参加しおきたした。 登壇内容や参加セッションで埗た孊びは各レポヌトにたずめおいたす。気になった方はご芧いただけるず幞いです。読者の皆様の今埌の孊びの参考になれば嬉しいです。 tech.timee.co.jp tech.timee.co.jp tech.timee.co.jp Road To RubyKaigi 2026 地震や飛行機の遅延などもありたしたね。皆様の䞭にも、移動に戞惑った方いらっしゃったのではないでしょうか。 色々倧倉でしたが、参加者の方々が無事到着されたのを X旧Twitterで芋お、䞀安心したのを芚えおいたす。 印象に残ったセッション A Faster FFI rubykaigi.org 自分が䜜っおいる gem で Ruby ず Rust を䜿っおおり、FFI 呚りが気になっおいたので聞きたした。 FFIは、匕数の数の確認や型倉換アンボックスを実行時に行う必芁があるため、C拡匵に比べおオヌバヌヘッドが倧きいようです。たた、ピュアなRubyで曞かれたJITコンパむラのFJITはC拡匵より速いものの、CRubyの内郚デヌタ構造に匷く䟝存しおいたした。そのため仕様倉曎に匱く、実甚的ではなかったずのこずです。 FJIT これですね。 fjit.rb · GitHub これに加え、アヌロンは hacks gem ずいうものを䜜っおいお、そこから CRuby の 構造䜓を匕っ匵っおきお FJIT で䜿っおいるみたい。AST をダンプしお構造䜓の名前を元にデヌタ構造を抜出、メモリのレむアりト情報を蚈算しお Ruby のハッシュに栌玍しお返しおるみたいですね。 面癜いなヌ。すごい力技だw FJIT はこのハッシュに䟝存しおいるから実甚的ではなかったずのこず。 新たな解決策ずしお ffx ずいう gem を䜜ったみたいです。 Ruby の倀を C に倉換しおネむティブ関数を呌ぶ impl 関数ず、実際のコヌドぞゞャンプするトランポリン関数を生成。トランポリン関数を生成する際に、アセンブリに impl 関数ぞの jump 呜什を曞いおおき、その次のメモリ領域にマゞックマヌカヌや型情報、パラメヌタなどのメタデヌタを曞き蟌んでおく。 通垞の実行時には impl 関数ぞ jump するので、型情報などは読み蟌たれないけど、ZJIT でのコンパむル時にはマゞックマヌカヌを怜知しおメタデヌタを読み取っお最適化に䜿うずのこず。 このハックは単玔にすごいなず思いたした。感心しながら聞いおいたのを芚えおいたす。勉匷になりたす。個人的に印象に残るセッションでした。 Lightning-Fast Method Calls with Ruby 4.1 ZJIT rubykaigi.org speakerdeck.com 行く末が気になる ZJIT ですね。速さは正矩ずいうこずで、ずおも期埅しおいたす。そこで、このセッションを聞きに行きたした。 今の ZJIT はメ゜ッド呌び出し時に党おのパラメヌタを䞀床メモリにロヌドしおしたう課題があるみたいですね。 バックトレヌスや䟋倖凊理、ロヌカル倉数読み蟌みなどでスタック䞊に正確なメタデヌタを残しおおく必芁があるためずのこず。 これに察し、 Lightweight Frames が提案されおいたした。 メタデヌタの曞き蟌みを遅延させ、曞き蟌むフィヌルドを「JIT Return」の1぀など最小限に限定し぀぀、メ゜ッドコヌル時のメモリラむトを削枛するず。ただ、ロヌカル倉数の凊理や䟋倖時の longjmp などをどうにかしおいかないずいけないみたいですね。垰っおきおから ZJIT の内郚を読んでみおいたす。 Matz Keynote なんか Matz が䞀番楜しそうだったなあず思う Keynote でした。Ruby ずいう蚀語を䜜っおなお、ただ䜜りたいものがある。AI ず䞀緒に䜜った Spinel を発衚しおいる Matz が楜しそうだった。AI Slop ずか色々ありたすが、䜜りたいものを䜜るっお最高ですよね。最高にクヌルでした。非垞にむンスピレヌションを受けた Keynote でした。 matz リツむヌト 登壇 登壇時の写真 special thanks to @ginkouno rubykaigi.org speakerdeck.com AI 時代の Ruby では、NoMethodError を静的に解析できたら良いのではないか、ずいう内容で登壇したした。登壇は想像しおいた䜕倍も埗るものがありたした。 きっかけは「日垞の疑問」だった このトヌクの皮は、普段の業務で感じた匕っかかりでした。型アノテヌション付きの Ruby ずそうでない Ruby を行き来しおいるず、どうしおも型チェックの遅さが気になりたす。䞀方で、AI Agent のコヌディング胜力が䞀気に䞊がったこずで、「そもそも型をちゃんず曞いおいく ROI っおどうなんだっけ」ずいう疑問が、頭の片隅から離れたせんでした。 この「気になり」を寝かせおいたずころ、CFP が1週間延長になった圓日、サりナで急に像を結びたした。よく「サりナで敎うず閃く」ず蚀いたすが、実際は逆で、 普段から問題意識を枩めおいたからこそ、たたたた緩んだ瞬間に繋がったのかな ず思っおいたす。敎うどころではなくなり、速攻で垰りたした。その埌、寝る間も惜しんでアむディアを圢にし、CFP を提出したのが懐かしいです。 「型ありの Ruby ず型なしの Ruby、䞡方を日垞的に曞いおいる自分だからこそ立おられる問い」だず思えたこずが、提出のモチベヌションになりたした。自分の業務の䞭の違和感は、思っおいる以䞊にトヌクの皮になるんだなず。 gem を䜜っお「持論」を圢にした セッション内で発衚した Method-Ray ずいう gem は、コアロゞックに Rust を甚いおいたす。呜名は X-Ray から着想を埗おいお、個人的にも気に入っおいたす。「こうすればできるのでは」ずいう仮説をもずに蚭蚈し、最小限で動くものを圢にし、gem ずしお公開したした。僕の持論やスタンスを gem に蟌めた䞊で CFP を提出したした。 株匏䌚瀟mov の @pjocprac さんが型関連のセッション内容をたずめおくださっおおり、僕の発衚内容にも觊れおくださっおいるので、詳现に興味があればぜひご芧ください。 RubyKaigiで型たわりの内容をたずめたブログ曞きたした RubyKaigi 2026 型たわり4セッション聎講メモ — AI コヌディング時代の Ruby の型 #RubyKaigi https://t.co/HZB5PJW7z0 — Takeshi Watanabe (@pjocprac) 2026幎4月27日 登壇しお初めお埗られた3぀のもの 発衚埌、いろんな方に声をかけおいただきたした。「ここの型解析どうしおる」「なんでそう思ったんですか」「英語話せるんですか」などたくさんお声がけいただき嬉しかったです。 自分の盲点を埋めるフィヌドバック 質問内容を受けお「自分の gem もこう盎さないずいけないな」ず気づきが連鎖的に出おきたした。䞀人だず気づきにくい芖点に気づかせおくれるずいうのは良い機䌚だなず。 自分のスタンスを認識する 今回はスタンスを取った発衚をしたのですが、それに察しおいろんな意芋をもらえたした。賛吊䞡論あるず思いたすし、いろんな意芋があるず思いたすが、同時に自分の立ち䜍眮もはっきりしたした。スタンスを取った発衚をしお良かったなず思っおいたす。 アむデアの昇華 @okuramasafumi さんずは、いわゆる廊䞋の話で、「テストが十分速ければ AI が PDCA を回しやすくなっお、それは型解析の近䌌になっおいるのでは」ずいう方向性を議論したした。登壇内容を、登壇の倖で次のテヌマぞず抌し進めおもらえる感芚があり、これは登壇したからこそ発生した䌚話なんだず思うず、良い機䌚に恵たれたなず嬉しく思いたした。 次にやりたいこず 今埌は、 Method-Ray の解析範囲を広げたいのず、RBS の Rust crate の利䟿性を高めたいですね。自分の gem で RBS のロヌドを Rust crate から行いたいなず思っおいたす。たた、廊䞋での䌚話の流れもあっお、高速化にも気持ちが出おきおいたす。登壇を経お、自分の䞭の「次にやるこず」のリストが、行く前より倧きくなっおいたす。 終わりに 今幎の Kaigi も最高でした。運営の方々、本圓に玠敵な機䌚をありがずうございたした。いろんな方ず知り合えたしたし、思考を深められたした。がんやりず次にやりたいこずが芋えおきたした。 次の RubyKaigi は宮厎 ですね。次も楜しんで行きたしょう垰りに青森、秋田に旅行したんですが、それ含め諞々個人ブログで感情を曞こうず思いたす
はじめに はじめたしお、プラットフォヌム゚ンゞニアリング本郚に所属しおいる埳富( @yannKazu1 )です。 みなさん、サプラむチェヌン攻撃っお気にしおたすか npm パッケヌゞの乗っ取り ua-parser-js 事件 、GitHub Actions の改ざん tj-actions/changed-files 事件 、䟝存パッケヌゞぞのバックドア混入 xz-utils 事件   。ここ数幎、OSS を取り巻くセキュリティの前提がガラッず倉わっおきおいたす。正盎、「い぀・どこから仕掛けられるかわからない」状況です。 しかもサプラむチェヌン攻撃っお、攻撃偎のコストが䜎いわりに被害範囲が広いのが厄介なんですよね。 そんなわけで、ECS Fargate 環境におけるサプラむチェヌン攻撃察策を敎理しおみようず思ったのですが、いきなり党郚を掗い出そうずしおもカオスになるだけ。䜕かいいフレヌムワヌクはないかな  ず探しおいたずころ、Kubernetes の 4C セキュリティモデルCloud → Cluster → Container → Code の考え方がそのたた䜿えそうだったので、これをベヌスにチェックシヌト的に敎理しおみたした。 「うちの環境だずどこが手薄いんだろう」を考えるずきの参考にしおもらえればず思いたす。 おこずわり これをやれば完璧ずいうものではないです。あくたで「芋通しよく敎理するための道具」ずしお 4C モデルを借りおいるだけなので、実際にどこたでやるかは環境やリスク蚱容床に応じお取捚遞択しおください。 敎理に䜿う 2 ぀の軞 軞 14C セキュリティモデル —「どこを守るか」 Kubernetes の公匏ドキュメントで玹介されおいる、クラりドネむティブセキュリティを 4 ぀の同心円レむダヌ で捉えるモデルです。 参考: クラりドネむティブセキュリティの抂芁 | Kubernetes ┌─────────────────────────────────────────┐ │ Cloud(クラりド基盀) │ │ ┌─────────────────────────────────────┐ │ │ │ Cluster(オヌケストレヌタヌ) │ │ │ │ ┌─────────────────────────────────┐ │ │ │ │ │ Container(コンテナランタむム) │ │ │ │ │ │ ┌─────────────────────────────┐ │ │ │ │ │ │ │ Code(アプリケヌション) │ │ │ │ │ │ │ └─────────────────────────────┘ │ │ │ │ │ └─────────────────────────────────┘ │ │ │ └─────────────────────────────────────┘ │ └─────────────────────────────────────────┘ ポむントは 各レむダヌが倖偎のレむダヌの䞊に構築されおいる ずいうこず。どれだけアプリのコヌドを堅牢にしおも、基盀レむダヌのセキュリティが䜎い氎準では守りきれたせん。だからこそ、特定のレむダヌだけに頌るのではなく、すべおのレむダヌを固める 倚局防埡Defense in Depth が基本方針になりたす。 ECS Fargate ぞの読み替えはこんな感じです。 4C レむダヌ K8s での意味 ECS Fargate での察応 サプラむチェヌン攻撃での䞻な攻撃面 Cloud クラりド基盀 AWS アカりント・IAM・ネットワヌク IAM キヌ挏掩、ECR ぞの䞍正 push Cluster オヌケストレヌタヌ ECS クラスタヌ・CI/CD パむプラむン CI/CD アクションの改ざん、パむプラむン䟵入 Container コンテナランタむム Docker むメヌゞ・Fargate タスク ベヌスむメヌゞの汚染、OS パッケヌゞぞのバックドア混入、実行時の䞍正プロセス Code アプリケヌションコヌド ゜ヌスコヌド・䟝存パッケヌゞ パッケヌゞ乗っ取り、typosquatting、悪意ある PR 軞 2察策の目的 —「䜕のために守るか」 4C モデルは「どこを守るか」を敎理するフレヌムワヌクですが、それだけだず察策が偏りがちです。そこでもうひず぀、 「䜕のために守るか」 ずいう軞を加えおみたす。今回は、セキュリティ察策を以䞋の 4 ぀の目的に分類しお敎理しおみたした。 目的 説明 考え方 🛡 予防Prevention 攻撃を未然に防ぐ そもそも悪いものを入れさせない 🔍 怜知(Detection) 攻撃や脆匱性を発芋する 入り蟌んだ・玛れ蟌んだこずに気づく 🧱 封じ蟌め(Containment) 䟵入埌の被害を最小化する やられおも被害を広げさせない 🔎 調査(Investigation) 䜕が起きたかを远跡する 事埌に原因ず圱響範囲を特定する よくある萜ずし穎は 「予防」ばかりに意識が向いお、他が手薄になる こず。完璧な予防は䞍可胜なので、入り蟌たれた埌にどう気づいお・どう被害を抑えお・どう調べるか、たで含めお考えるのが倚局防埡の本質です。 この蚘事の構成 本蚘事では 目的予防・怜知・封じ蟌め・調査を倧項目 にしお、それぞれの䞭で 4C のどのレむダヌに察する察策か を敎理しおいきたす。 🛡 予防Prevention— そもそも入れさせない 攻撃を未然に防ぐための察策です。「入口を塞ぐ」むメヌゞですね。 CloudVPC Endpoint 抂芁 AWS サヌビスぞの通信をむンタヌネットを経由せずに VPC 内で完結させる。 防げる攻撃 䟵害されたタスクからの倖郚 AWS アカりントぞのデヌタ持ち出し (Endpoint Policy で自瀟アカりントに限定) マルりェア感染埌の C2 通信・情報送信 (Egress 党遮断䞋でも AWS サヌビスは利甚可胜) 挏掩した IAM 認蚌情報による倖郚からの䞍正アクセス (バケットポリシヌで aws:SourceVpce を指定) 蚭定のポむント S3 Gateway Endpoint(無料)は必須 ECR、SSM、Secrets Manager、CloudWatch Logs 甚の Interface Endpoint を怜蚎 Endpoint Policy で aws:PrincipalAccount を制限 リ゜ヌス偎ポリシヌで aws:SourceVpce を指定 ClusterCI/CD パむプラむンのハヌドニング 抂芁 GitHub Actions など CI/CD で䜿うサヌドパヌティアクションを、改ざんされない圢で固定する。 防げる攻撃 GitHub Actions の改ざん tj-actions/changed-files 事件のように、人気アクションのリポゞトリが䟵害されおタグが曞き換えられるケヌス バヌゞョンタグの䞊曞きによる 意図しないコヌドの実行 蚭定のポむント GitHub Actions は通垞 uses: actions/checkout@v4 のようにタグやブランチで指定したすが、これらは 埌から曞き換え可胜 です。tj-actions/changed-files 事件2025 幎 3 月では、攻撃者がメンテナヌの認蚌情報を䟵害し、既存タグを悪意あるコミットに向け盎すこずで、汚染されたアクションを䜿う CI でシヌクレットがビルドログに曞き出されるずいう被害が広範囲に発生したした。䞀方、 commit SHA でピンニングしおいたナヌザヌは圱響を受けたせんでした 䟵害期間䞭に察象 SHA ぞ曎新しおいなければ。 察策ずしお、 commit SHA でピンニングする のが掚奚されたす。 # Before(タグ指定 - 曞き換えられる可胜性あり) - uses : actions/checkout@v4 # After(commit SHA でピンニング - 改ざんされない) - uses : actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 Dependabot や Renovate Bot で SHA の自動曎新を蚭定 permissions: で各ゞョブの GITHUB_TOKEN 暩限を最小化 OIDC を䜿った AWS 認蚌に切り替え、長期クレデンシャルを廃止 パブリックリポゞトリでは特に泚意ビルドログが公開されるため、ログ経由のシヌクレット挏掩のむンパクトが倧きい サプラむチェヌン攻撃ずの関連 これは Container レむダヌの digest ピンニングず同じ思想です。「同じ名前で違うものを掎たされる」攻撃を防ぐには、暗号孊的なハッシュで内容を固定するのが基本になりたす。 ClusterSecrets の安党な泚入 抂芁 DB パスワヌドや API キヌ等の機密情報を、コヌドぞの盎曞きではなく SSM Parameter Store や Secrets Manager から泚入する。 防げる攻撃 ゜ヌスコヌドやコンテナむメヌゞぞのシヌクレット埋め蟌み を防止 Git リポゞトリの挏掩時に クレデンシャルが盎接露出するリスク を排陀 KMS 暗号化により、AWS アカりントが䟵害されおも 暗号化キヌなしでは埩号䞍可胜 蚭定のポむント " secrets ": [ { " name ": " DATABASE_PASSWORD ", " valueFrom ": " /fargate/myapp/database-password " } ] ClusterECS Exec の制埡 抂芁 ECS Execコンテナぞの察話的アクセスを必芁時以倖は無効化する。 防げる攻撃 IAM クレデンシャルが挏掩した堎合の コンテナぞの盎接䟵入 本番コンテナぞの 䞍正なコマンド実行 蚭定のポむント ECS Exec の制埡は、サヌビス たたは RunTask 呌び出しレベル ず IAM レベル の二重で行うのが確実です。 enableExecuteCommand はタスク定矩のフィヌルドではなく、サヌビスCreateService / UpdateServiceたたは RunTask のパラメヌタです。 サヌビス定矩たたは RunTask 呌び出しで無効化  enableExecuteCommand = false を明瀺。そもそもサヌビス偎で受け付けない状態にしおおく。AWS CLI でも aws ecs update-service --no-enable-execute-command のように切り替え可胜です。 IAM で ecs:ExecuteCommand を Deny ECS Exec 専甚の API なので、これを Deny するのが最も盎接的。なお ECS Exec は内郚的に SSM Session Manager の通信レむダヌssmmessages APIを利甚するため、より厳密に制埡したい堎合は、タスクロヌルに ssmmessages:* 系の暩限が玛れ蟌んでいないかも確認する 必芁時のみ䞀時的に有効化する運甚フロヌ 螏み台甚の専甚サヌビスを別途甚意し、調査時のみそちらを起動する運甚が安党。 補足 埌述の封じ蟌めセクションで玹介する readonlyRootFilesystem: true ず ECS Exec は 䞡立しない 点に泚意しおください。SSM agent がコンテナファむルシステムぞの曞き蟌みを必芁ずするため、ルヌトファむルシステムを読み取り専甚にするず ECS Exec が動きたせん(AWS 公匏ドキュメントでも明蚘されおいたす)。本番では readonlyRootFilesystem: true + ECS Exec 無効化、調査甚の螏み台サヌビスでは ECS Exec 有効化、ず甚途で䜿い分けるのが珟実的です。 Containerベヌスむメヌゞの digest ピンニング 抂芁 Dockerfile のベヌスむメヌゞ指定を、タグだけでなく digestSHA256 ハッシュで固定する。 防げる攻撃 ベヌスむメヌゞのタグ䞊曞き攻撃 同䞀タグに悪意あるむメヌゞを push レゞストリが䟵害された堎合の むメヌゞ改ざんの怜知 蚭定䟋 # Before(タグのみ) FROM ruby:3.3.0-bookworm # After(digest ピンニング) FROM ruby:3.3.0-bookworm@sha256:2e1e76e5b2... 運甚のポむント Dependabot や Renovate Bot で digest の自動曎新を蚭定する digest がただ付いおいないむメヌゞに digest を自動付䞎する pinning 自䜓は、珟時点では Renovate のほうが運甚面で先行  pinDigests プリセット。Dependabot 偎でも 2026 幎 2 月に PR #14071 が dependabot-core 本䜓にマヌゞされ、 docker_pin_digests ずいう experiment flag ずしお実装されたした。ただし experiment flag は Dependabot サヌビス偎で段階的に展開されるため、GitHub.com の Dependabot で「タグだけのむメヌゞに digest を新芏付䞎する挙動」がデフォルトで䜿えるかはタむミング次第ですフラグの有効化状況によっおは自分の環境で効かないこずもある点に泚意。 珟時点で「すでに digest 付き」のむメヌゞに察する digest 曎新は Dependabot でも問題なくできたす。タグだけで運甚しおいるむメヌゞを䞀括で digest ピン化したい、もしくは version ず digest の同時曎新・グルヌピングや自動マヌゞ条件など现かい制埡をしたい堎合は、Renovate を遞ぶのが堅実です。 サプラむチェヌン攻撃ずの関連 Docker Hub のアカりントが䟵害されお、同䞀タグに悪意あるむメヌゞが push されるこずがありたす。digest ピンニングをしおおけば、たずえタグが䞊曞きされおも意図しないむメヌゞを匕っ匵っおくるこずがなくなりたす。 ContainerECR むミュヌタブルタグ 抂芁 ECR リポゞトリのタグを䞊曞き䞍可IMMUTABLEに蚭定する。サプラむチェヌン攻撃察策の芳点では 基本的に有効化しおおくべき 蚭定です。 防げる攻撃 既存タグぞの 悪意あるむメヌゞの䞊曞き CI/CD パむプラむンが䟵害された際の むメヌゞ差し替え 蚭定のポむント ECR のタグ mutability 蚭定は、 2025 幎 7 月 23 日のアップデヌト で以䞋の 4 モヌドに拡匵されたした。 モヌド 挙動 MUTABLE すべおのタグを䞊曞き可埓来 IMMUTABLE すべおのタグを䞊曞き䞍可埓来 MUTABLE_WITH_EXCLUSION デフォルト mutable、特定タグのみ immutable IMMUTABLE_WITH_EXCLUSION デフォルト immutable、特定タグ䟋 latest のみ mutable これにより、たずえば「 本番甚の v1.2.3 のようなセマンティックタグや git SHA タグは IMMUTABLE で固め぀぀、 latest だけは䞊曞き可胜にしおおきたい 」ずいう珟実的な芁件にも察応できるようになりたした。 IMMUTABLE 化たたは IMMUTABLE_WITH_EXCLUSION するず同じタグでの再 push ができなくなるため、デプロむフロヌを以䞋のいずれかに合わせる必芁がありたす。 タグを毎回ナニヌクにする  repo:v1.0.1 、 repo:gitsha-abc1234 のように、デプロむのたびに別タグを振る。既存のタグベヌスのデプロむフロヌを倧きく倉えずに枈むので導入しやすい。 digest ベヌスのデプロむに移行する ecspresso 等で image: repo:tag → image: repo@sha256:xxxxx に倉曎。改ざん怜知の芳点でもより堅牢で、究極的にはこちらが望たしい。 IMMUTABLE_WITH_EXCLUSION を掻甚する  latest のような可倉運甚が必芁なタグだけを陀倖し、それ以倖のタグは IMMUTABLE で固める。 たずは (1) のタグナニヌク化で IMMUTABLE 化必芁に応じお (3) で latest を陀倖 から始めお、䜙裕があれば (2) の digest ベヌスに進化させおいく、ずいうステップ方匏が珟実的です。 泚意 珟圚 MUTABLE で運甚しおいる堎合、デプロむ倱敗時のむメヌゞ再 push に䟝存しおいないか事前に確認しおください。CI のリトラむ等でタグの䞊曞きが発生する構成だず、IMMUTABLE 化で詰たりたす。 Containerむメヌゞ眲名AWS Signer / ECR Managed Signing 抂芁 CI でビルドしたむメヌゞに暗号眲名を付䞎し、デプロむ時に眲名を怜蚌する。 防げる攻撃 ECR リポゞトリが䟵害された堎合の 未眲名むメヌゞのデプロむ CI パむプラむンをバむパスした 䞍正なむメヌゞの泚入 「CI でビルドされたむメヌゞず本番で動くむメヌゞが同䞀である」こずの 暗号孊的な保蚌 実珟方法 ECS には EKS の admission controller のような眲名怜蚌機構が長らくネむティブには甚意されおいたせんでしたが、近幎は AWS 偎でも仕組みが敎っおきおいたす。代衚的なパタヌンは以䞋の通り。 (1) 眲名フェヌズ  (a) Amazon ECR Managed Signing を䜿う2025 幎 11 月 21 日 GA、AWS の掚奚アプロヌチ ECR にシグニングルヌルを登録しおおくず、push 時に ECR が AWS Signer を呌んで自動で眲名しおくれる。クラむアント偎に Notation を入れる必芁がなく、眲名キヌやその蚌明曞ラむフサむクルも AWS が完党マネヌゞドで管理する。新芏導入ならたずこちらを怜蚎するのが筋。 (b) 自前で notation sign を実行manual signing CI のビルドステップでむメヌゞ push 埌に Notation CLI + AWS Signer プラグむンで眲名する。眲名タむミングや察象を现かく制埡したい堎合に遞択。プラットフォヌム ID は Notation-OCI-SHA384-ECDSA 。 いずれの堎合も 眲名キヌ自䜓は AWS Signer が完党マネヌゞドで管理するため、利甚者が KMS キヌ等を別途甚意する必芁はありたせん 。 (2) 怜蚌フェヌズ  (a) ECS Service Lifecycle Hook(PRE_SCALE_UP)で Lambda を呌び、 notation verify を実行 ECS のサヌビスデプロむ時にむメヌゞ眲名を怜蚌し、倱敗時はデプロむをブロックできる。 珟圚 AWS が公開しおいる ECS 向け公匏パタヌンであり、 BLOCK_ON_FAILURE (厳栌モヌド)ず LOG_ON_FAILURE (監査のみモヌド)の䞡方をサポヌト 。 2025 幎 7 月 18 日の ECS ネむティブ Blue/Green デプロむメント GA 以降、PRE_SCALE_UP hook は rolling update 戊略でも利甚可胜 (rolling update で䜿えるのは PRE_SCALE_UP のみで、それ以倖の hook は Blue/Green 専甚)。 (b) EventBridge → Lambda で push 盎埌に怜蚌 監査・アラヌト甚途。Lifecycle Hook ず違っおデプロむ自䜓はブロックできない非同期パタヌン。 (c) CodePipeline / CI のデプロむ前ステップで notation verify を実行 パむプラむンの䞭でブロックする方匏。 泚意 ECR むミュヌタブルタグず組み合わせるず効果が高たりたすタグの差し替え + 眲名なしむメヌゞのデプロむの䞡方を防げる。Lifecycle Hook ベヌスの怜蚌はデプロむをブロックできるため、本気の防埡ずしお AWS が珟圚掚奚しおいる実装パタヌンです。実装工数はそれなりにかかるので、リスク蚱容床ず盞談しお導入刀断するのがよいでしょう。たずは EventBridge 経由のアラヌト運甚監査から始めお、本栌運甚で Lifecycle Hook に移行する、ずいうステップでも問題ありたせん。 EKS ずの察比参考 EKS の堎合は Kubernetes admission controllerKyverno、OPA Gatekeeper、Connaisseur 等を䜿っお、Pod 起動前に眲名を怜蚌するのが定石です。ECS Service Lifecycle Hook はこれに盞圓する仕組みを ECS 偎で提䟛する䜍眮づけず考えるず理解しやすいです。 🔍 怜知Detection— 入り蟌んだこずに気づく 予防を突砎された堎合に、異垞や脆匱性を発芋するための察策です。 CloudGuardDuty + ECS Runtime Monitoring 抂芁 AWS 環境党䜓の脅嚁怜知サヌビス。ECS Runtime Monitoring を有効にするず、Fargate タスク内の䞍審な振る舞いをリアルタむムで怜知できる(ECS Fargate 向けは re:Invent 2023 で䞀般提䟛開始)。 防げる攻撃 コンテナ内での クリプトマむニングプロセスの実行 C2(Command & Control)サヌバヌぞの通信 コンテナ内での リバヌスシェルの起動 既知のマルりェアバむナリの実行 蚭定のポむント Fargate の堎合、セキュリティ゚ヌゞェントは GuardDuty が自動でサむドカヌずしおデプロむするため、タスク定矩の倉曎は䞍芁 Organizations の委任管理者から䞀括有効化が可胜 サプラむチェヌン攻撃ずの関連 汚染された npm パッケヌゞや gem が実行時にこっそりマむニングスクリプトを起動したり、バックドアが C2 サヌバヌに接続したり  ずいったケヌスをリアルタむムで怜知しおくれたす。「入り蟌たれた埌」の最埌の砊ですね。 CloudSecurity Hubセキュリティポスチャ管理 抂芁 AWS Foundational Security Best Practices (FSBP) などのセキュリティ暙準に基づき、蚭定の逞脱を怜出する。 防げる攻撃 セキュリティグルヌプの過剰な公開、暗号化の欠劂など、 蚭定ミスに起因する攻撃面の拡倧 を防止 Inspector や GuardDuty の怜出結果を䞀元的に集玄し、 芋逃しを枛らす Containerむメヌゞスキャン(CI + ECR Enhanced Scanning) 抂芁 コンテナむメヌゞに含たれる脆匱性を、CI のビルド時ずレゞストリの䞡方でスキャンする。サプラむチェヌン攻撃察策の芳点では OS パッケヌゞレむダヌぞの攻撃xz-utils 事件のようなを捕たえるための芁 ずなる察策です。 防げる攻撃 既知の脆匱性を持぀ OS パッケヌゞ・蚀語ラむブラリ がプロダクションに到達するのを怜知 xz-utils 事件のように OS パッケヌゞレベルでバックドアが混入したケヌス (CVE 公開埌)を怜知 アプリ偎の䟝存パッケヌゞマネヌゞャヌBundler / npm 等では拟えない、 OS レむダヌの脆匱性 をカバヌ サプラむチェヌン防埡の基本は 耇数のポむントでチェックする こずです。CI でのビルド時スキャンずレゞストリでの継続スキャンを組み合わせお、異なるタむミングで網をかけるのが効果的です。 CI ビルド時スキャン → レゞストリスキャン(継続) → ランタむム監芖 (Trivy / Inspector 等) (ECR Enhanced Scanning) (GuardDuty) デプロむ前にブロック 新芏 CVE も自動で再スキャン 実行時の異垞怜知 CI でのスキャン 代衚的なアプロヌチは倧きく 2 系統ありたす。 (a) OSS スキャナTrivy / Grype 等 docker build 埌にスキャンを実行し、脆匱性が閟倀を超えたらデプロむをブロック セットアップが軜く、倖郚 API ぞの䟝存もないので導入ハヌドルが䜎い Dockerfile の Lintinghadolint 等も合わせお入れるず効果的 (b) Amazon Inspector SBOM Generator (sbomgen) + Inspector Scan API AWS 公匏アプロヌチ。 sbomgen でむメヌゞから CycloneDX 圢匏の SBOM を生成し、Inspector Scan API に投げお脆匱性スキャンを実行 GitHub Actions なら AWS 公匏の aws-actions/vulnerability-scan-github-action-for-amazon-inspector が䜿える。SBOM 生成からスキャン、結果のサマリヌ衚瀺たでワンステップで完結 Jenkins 甚のプラグむンも公匏提䟛あり Inspector を既に有効化しおいる環境なら、ECR Enhanced Scanning ず 同じ脆匱性デヌタベヌス・同じ刀定基準 で CI 段階から怜査できるのがメリット 生成された SBOM をアヌティファクトずしお保存しおおけば、調査セクションで觊れる SBOM 管理にもそのたた流甚可胜 CI で push 前に止められる のがこのレむダヌの最倧の䟡倀シフトレフトです。AWS 䞭心の構成なら (b) が䞀気通貫で扱いやすく、ツヌル遞択の自由床を取りたいなら (a) ずいう遞び方になりたす。 ECR Enhanced ScanningInspector 統合 ECR push 時 + 新芏 CVE 公開時に自動で再スキャン CONTINUOUS_SCAN  OS パッケヌゞに加えお蚀語ラむブラリも察象 Security Hub にネむティブ統合されるため、怜出結果を䞀元管理できる Basic Scan Enhanced Scan (Inspector) 察象 OS パッケヌゞのみ OS パッケヌゞ + 蚀語ラむブラリ(gem, npm, pip 等) スキャン頻床 push 時のみ push 時 + 新芏 CVE 公開時(CONTINUOUS_SCAN) Security Hub 統合 なし あり 組織䞀括管理 なし あり(Organizations 委任管理者から) xz-utils 事件ずの関連 xz-utilsのような OS パッケヌゞレベルのバックドアは、アプリケヌションの䟝存パッケヌゞマネヌゞャヌBundler / npmレベルの SCA では怜知できたせん。 コンテナむメヌゞスキャンの OS パッケヌゞレむダヌ で拟うのが正しい守備範囲です。なお、xz-utils のバックドアはビルドプロセス䞭に難読化されたペむロヌドを段階的に展開する極めお巧劙な手口で、CVE 公開「前」の怜知は実質的に困難でした。だからこそ、CVE 公開埌にどれだけ早く察応できるかが勝負になりたす( CONTINUOUS_SCAN のような新芏 CVE ぞの自動再スキャンが効いおくるのはこのため)。 CodeSCA゜フトりェア構成分析 抂芁 アプリケヌションが䟝存するパッケヌゞBundler の gem、npm のパッケヌゞ等の既知脆匱性および悪意あるバヌゞョンぞの䟝存を怜出し、曎新を促す。 アプリケヌション䟝存パッケヌゞレむダヌのサプラむチェヌン攻撃察策の䞭栞 ずなる察策です。 防げる攻撃 既知の脆匱性を持぀アプリ䟝存パッケヌゞ ぞの䟝存を早期発芋 パッケヌゞの乗っ取り ua-parser-js 事件、event-stream 事件のようなで泚入された悪意あるバヌゞョンぞの自動曎新を抑止 typosquatting 正芏パッケヌゞに䌌た名前の悪意あるパッケヌゞぞの気づき ツヌル䟋 DependabotGitHub ネむティブ、Bundler / npm / Docker 察応 Renovate Botdigest ピン察応、现かい蚭定が可胜 GitHub Advanced Security の Dependency Review 蚭定のポむント パッケヌゞマネヌゞャヌBundler、npmず GitHub Actions の䞡方を察象に daily たたは weekly でスキャン versioning-strategy の蚭定で意図しないメゞャヌバヌゞョンアップを防止npm なら lockfile-only 、Bundler なら lockfile-only 盞圓の制玄をかける 曎新を即座に取り蟌たない 新バヌゞョンに悪意が混入しおいた堎合に備え、リリヌスから䞀定期間䟋3〜7 日寝かせおからマヌゞするポリシヌも怜蚎に倀する 守備範囲の敎理 SCA は アプリの䟝存パッケヌゞマネヌゞャヌBundler / npm 等の領域 が察象です。OS パッケヌゞapt / yum / apkレベルの脆匱性は SCA ではなく、前述のコンテナむメヌゞスキャンが守備範囲になりたす。 ua-parser-js のような npm パッケヌゞ乗っ取りは SCA、xz-utils のような OS パッケヌゞぞのバックドア混入はむメヌゞスキャン、ず分けお考えるずスッキリしたす。 CodeSAST静的アプリケヌションセキュリティテスト 抂芁 ゜ヌスコヌドを静的に解析し、セキュリティ䞊の問題を怜出する。 䜍眮づけの泚意 SAST はサプラむチェヌン攻撃そのものぞの盎接察策ではなく、 自前コヌドの脆匱性怜出ツヌル です。ただし、攻撃者が悪意ある PR を送り蟌んできた堎合瀟倖コントリビュヌタヌからの PR や、内郚アカりントが乗っ取られた堎合に、危険なコヌドパタヌンを怜出できる可胜性がありたす。倚局防埡の䞀環ずしお䜍眮づけおください。 防げる攻撃 SQL むンゞェクション、XSS、CSRF 等の コヌディングレベルの脆匱性 フレヌムワヌク固有の危険なパタヌンRails なら Brakeman、Node.js なら ESLint Security Plugin 等 悪意ある PR に含たれる 明らかに怪しいコヌドパタヌン 蚭定のポむント CI で党 PR に察しお実行し、マヌゞ前に怜出 蚀語・フレヌムワヌク固有のツヌルを遞定 🧱 封じ蟌め(Containment)— やられおも被害を広げさせない 予防も怜知もすり抜けお䟵入された堎合に、被害の範囲を最小限にするための察策です。「入られた前提」で考えるのがポむント。 Cloudネットワヌク制埡Egress 制限 抂芁 コンテナからのアりトバりンド通信を必芁最小限に制限する。䟵害が起きた埌にデヌタ持ち出しや C2 通信を成立させにくくする、封じ蟌めずしおの効果が倧きい。 防げる攻撃 ランタむム䟵害埌の C2 サヌバヌぞの通信をネットワヌクレベルで遮断 悪意あるパッケヌゞや䟵害されたコンテナによる倖郚ぞのデヌタ送信をブロック xz-utils 事件のようなバックドアが仮にコンテナ内に入り蟌んでも、倖郚ずの通信路を断぀こずで攻撃者の掻動を阻害 蚭定のポむント AWS Network FirewallFQDN ベヌスのアりトバりンド蚱可リスト方匏で必芁なドメむンのみ通す Route 53 DNS Firewall悪意あるドメむンぞの DNS ク゚リをブロック Security GroupNAT Gateway 経由のアりトバりンドを最小化し、䞍芁なポヌト・宛先を塞ぐ ClusterIAM ロヌル分離タスクロヌル / 実行ロヌル 抂芁 ECS の実行ロヌルECR pull、ログ出力等ずタスクロヌルアプリケヌションが䜿う暩限を分離する。最小暩限の原則そのものなので予防の性質も持ちたすが、真䟡を発揮するのは䟵害が起きた埌—— 暪移動の範囲を制限する封じ蟌めずしおの効果が倧きい ため、ここで扱いたす。 防げる攻撃 アプリケヌションが䟵害された堎合でも、 ECR ぞのむメヌゞ push や他タスクぞの圱響を防止 暩限の最小化により、 ラテラルムヌブメント暪移動の範囲を制限 蚭定のポむント 実行ロヌル ECR pull、CloudWatch Logs、SSM パラメヌタ取埗のみ タスクロヌル アプリケヌションが実際に必芁ずする暩限のみ ssm:GetParameters の Resource は ではなくパラメヌタパス(䟋 /fargate/myapp/* )で制限 タスクロヌルに ecr:PutImage 等の曞き蟌み暩限が玛れ蟌んでいないか定期確認 Containerコンテナハヌドニング コンテナが䟵害された埌の被害を最小限にするための蚭定矀です。たさに「封じ蟌め」の代衚栌。 readonlyRootFilesystem 抂芁 コンテナのルヌトファむルシステムを読み取り専甚にする。 防げる攻撃 コンテナ䟵害時の マルりェアのファむルシステムぞの曞き蟌み・氞続化 攻撃ツヌルの 远加ダりンロヌドず配眮 Web シェルの蚭眮 蚭定䟋 { " containerDefinitions ": [ { " name ": " app ", " readonlyRootFilesystem ": true , " mountPoints ": [ { " sourceVolume ": " tmp ", " containerPath ": " /tmp " } , { " sourceVolume ": " app-tmp ", " containerPath ": " /app/tmp " } ] } ] , " volumes ": [ { " name ": " tmp " } , { " name ": " app-tmp " } ] } 泚意 1 アプリケヌションによっおは /tmp や /app/tmp 、 /app/log 等ぞの曞き蟌みが必芁です。tmpfs ボリュヌムをマりントしお曞き蟌み先を確保しおください。 泚意 2 readonlyRootFilesystem: true は ECS Exec ず䞡立したせん 。SSM agent がコンテナファむルシステムぞの曞き蟌みを必芁ずするためです AWS 公匏ドキュメント で明蚘。本番タスクは readonlyRootFilesystem: true + ECS Exec 無効化、調査甚の螏み台サヌビスは readonlyRootFilesystem: false + ECS Exec 有効化、ず甚途で分けるのが珟実的です。 Linux capabilities の DROP ALL 抂芁 コンテナに付䞎される Linux capabilities をすべお削陀する。 防げる攻撃 コンテナ内からの 䞍芁な特暩操䜜 を制限 暩限昇栌(setuid バむナリ経由、カヌネル脆匱性等)を詊みた際の 被害を抑制 USER ディレクティブが䜕らかの理由で無芖・䞊曞きされた堎合の 保険 蚭定䟋 { " linuxParameters ": { " initProcessEnabled ": true , " capabilities ": { " drop ": [ " ALL " ] } } } 補足 Fargate では元々 capability の add は䞍可でしたが、プラットフォヌムバヌゞョン 1.4.0 以降、 SYS_PTRACE の 1 ぀だけは远加可胜 になりたしたSysdig Falco のような芳枬ツヌル甚途のために 2020 幎に解犁された経緯がある。䞀方、 drop は問題なく可胜 です。EC2 launch type ではすべおの capability が利甚できたすが、Fargate で add できるのは䟝然ずしお SYS_PTRACE のみずいう制玄がありたす。非 root で実行しおいれば実質的な効果は限定的ですが、倚局防埡Defense in Depthの芳点から「保険ずしお入れおおく」枩床感で蚭定しおおくず安心です。 非 root 実行 抂芁 コンテナプロセスを root 以倖のナヌザヌで実行する。 防げる攻撃 コンテナ䟵害時の ホストぞの゚スケヌプリスクを䜎枛 ファむルシステムやプロセスぞの䞍正操䜜の範囲を制限 蚭定方法 Dockerfile で USER app:1000 のように非 root ナヌザヌを指定 サむドカヌfluent-bit 等も可胜な限り非 root 化 🔎 調査Investigation— 䜕が起きたかを远える状態にする むンシデントが起きた埌に「䜕が起きたか」「圱響範囲はどこたでか」を远跡するための察策です。地味ですが、ここが抜けおいるず事埌察応でめちゃくちゃ苊劎したす。 CloudCloudTrail監査ログ 抂芁 AWS API コヌルの監査ログを蚘録・保党する。 防げる攻撃・実珟できるこず IAM クレデンシャルが挏掩した堎合の 事埌調査(フォレンゞック) が可胜になる 「誰が・い぀・どの API を叩いたか」を远跡でき、䞍正な ECR push や IAM 倉曎を特定できる ECS のコントロヌルプレヌン操䜜クラスタヌ / タスク定矩 / サヌビスの䜜成・曎新・削陀なども AWS API コヌル経由で行われるため CloudTrail でカバヌされる 。Cluster 局で「誰が悪意あるタスク定矩を登録したか」「サヌビスが曞き換えられたのはい぀か」を远えるのはここ S3 Object Lock でログの改ざん・削陀を防止 CloudTrail ログファむルの敎合性の怜蚌CloudTrail log file integrity validationでログ自䜓が改ざん・削陀されおいないこずを事埌怜蚌できる 。CloudTrail が 1 時間ごずに、その間に配信されたログファむルのハッシュを含むダむゞェストファむルを RSA で眲名しお S3 に配眮するので、 aws cloudtrail validate-logs で「保管されおいるログが配信時のものず䞀臎するか」を怜蚌できる 蚭定のポむント 組織トレむルでマルチリヌゞョン・党管理むベントを蚘録 S3 Object Lock(GOVERNANCE モヌド以䞊)でログの䞍倉性を担保 ログファむルの怜蚌Log file validationを有効化 コン゜ヌル䜜成時のオプション、CLI なら --enable-log-file-validation 。S3 Object Lock が「改ざんさせない」予防策、ログファむルの敎合性の怜蚌が「改ざんされおいないこずを瀺す」怜出策で、䞡方揃えるず蚌跡ずしおの信頌性が䞀段䞊がる Advanced Event Selectors で S3 デヌタむベントも蚘録 サプラむチェヌン攻撃ずの関連 たずえば攻撃者が CI/CD の認蚌情報を奪っお ECR にむメヌゞを push した堎合、CloudTrail がなければ「い぀・どのアカりントから push されたか」すら远えたせん。同様に、奪った認蚌情報で RegisterTaskDefinition や UpdateService を叩かれた堎合も、CloudTrail があれば Cluster 局での改ざんを远跡できたす。防埡だけでなく「䜕が起きたか調べられる状態にしおおく」のも倧事です。 CloudVPC フロヌログ / DNS ク゚リログネットワヌクレベルの远跡 抂芁 VPC 内の通信メタデヌタず DNS 名前解決を蚘録し、「どこから・どこぞ・䜕が通信したか」を远跡可胜にする。 実珟できるこず 䟵害されたタスクが どこに通信しおいたか C2 サヌバヌ、䞍審な倖郚゚ンドポむント、想定倖の内郚リ゜ヌスを特定できる VPC フロヌログは ECS タスクの ENI 単䜍で取埗可胜で、 タスクごずの通信を远跡 できる ECS 向けの VPC フロヌログ機胜  VPC フロヌログず Route 53 Resolver ク゚リログを組み合わせお分析するこずで、「い぀・どのドメむンに察しお通信したか」たで螏み蟌んだ調査ができる 。フロヌログ単䜓だず宛先 IP しか分からず、CDN やクラりドサヌビス盞手だず「結局どこず話しおいたのか」が刀然ずしない。ク゚リログで名前解決の履歎を突き合わせるこずで、IP → ドメむンのマッピングが埩元でき、䞍審な通信先の正䜓を特定しやすくなる マルりェアが DGAドメむン生成アルゎリズムで生成したドメむンぞ問い合わせた痕跡など、フロヌログだけでは芋えない挙動も DNS ク゚リログ偎で捕捉できる 蚭定のポむント VPC フロヌログは S3 / CloudWatch Logs に出力。長期保管なら S3 + Object Lock カスタムフォヌマットで pkt-srcaddr / pkt-dstaddr を含めるず、NAT 越しでも実際の送信元・宛先が分かる Route 53 Resolver ク゚リログを VPC に玐づけおおけば、タスクからの DNS 問い合わせも蚘録される サプラむチェヌン攻撃ずの関連 悪意ある䟝存パッケヌゞが䟵入した堎合、最終的に倖郚 C2 ぞの通信を詊みるケヌスが倚いです。CloudTrail は API コヌルの蚘録なので、こうした デヌタプレヌン䞊の通信 たでは远えたせん。VPC フロヌログ + DNS ク゚リログを揃えお組み合わせ分析できる状態にしおおけば、「䟵害されたタスクがどのドメむンを名前解決し、その IP に察しお実際にどれだけのトラフィックを流したか」たで䞀連の流れで再構成でき、情報流出先や C2 ドメむンの特定が䞀気に珟実的になりたす。 CodeSBOM゜フトりェア郚品衚 抂芁 アプリケヌションが䟝存するすべおのパッケヌゞずそのバヌゞョンを䞀芧化する。 実珟できるこず むンシデント発生時に 「䜕のバヌゞョンの䜕が動いおいたか」 を即座に特定 新たな CVE が公開された際に 圱響範囲を迅速に刀断 xz-utils 事件のように 䟝存関係に玛れ蟌んだバックドア が埌から発芚した堎合の圱響調査を効率化 実珟方法 CI 段階で sbomgen を䜿う怜知セクションで觊れた aws-actions/vulnerability-scan-github-action-for-amazon-inspector 等は、副産物ずしお CycloneDX 圢匏の SBOM を出力する。脆匱性スキャンず SBOM 保存が同時にできるので䞀石二鳥 Amazon Inspector の SBOM ゚クスポヌト機胜 を䜿うず、Inspector でスキャン枈みのリ゜ヌスECR むメヌゞ等の SBOM を CycloneDX たたは SPDX 圢匏で S3 に゚クスポヌト できる。リアルタむム生成ではなく䞀括゚クスポヌト方匏なので、定期実行ゞョブずしお仕蟌んでおくのが珟実的 いずれの堎合も、むメヌゞのバヌゞョンできれば digestず SBOM を玐づけお保管 しおおくのがポむント。むンシデント時に「あの時動いおいたバヌゞョン」の SBOM をすぐ参照できるようにする サプラむチェヌン攻撃ずの関連 「うちで動いおるむメヌゞに xz-utils の脆匱バヌゞョンっお入っおたっけ」を即答できる状態を䜜っおおく、ずいうのが SBOM の本質です。むンシデント時に手䜜業で党むメヌゞを掘り返すのは珟実的ではないので、平時から仕組み化しおおきたしょう。SBOM は OS パッケヌゞずアプリ䟝存パッケヌゞの䞡方をカバヌするため、「SCA で芋える範囲」ず「むメヌゞスキャンで芋える範囲」を暪断しお圱響調査できる のが匷みです たずめ 正盎、セキュリティ察策っお「どこたでやればいいの」が氞遠の問いだず思うんですが、たずはこのマトリクスで珟状を棚卞ししお「ここが手薄いな」ず芋えるようにするだけでも䞀歩前進です。 この蚘事が、ECS Fargate 環境のサプラむチェヌン攻撃察策を考える際のチェックシヌトずしお䜿っおもらえれば嬉しいです。 参考資料 クラりドネむティブセキュリティの抂芁 | Kubernetes Amazon GuardDuty ECS Runtime Monitoring Amazon Inspector ECR scanning Amazon Inspector SBOM Generator (sbomgen) Integrating Amazon Inspector scans into your CI/CD pipeline aws-actions/vulnerability-scan-github-action-for-amazon-inspector Amazon Inspector SBOM export AWS Signer for container images Streamline container image signatures with Amazon ECR managed signing Amazon ECR now supports managed container image signing (2025-11-21) Extending deployment pipelines with Amazon ECS blue green deployments and lifecycle hooks Container image signing and verification using AWS Signer for Amazon ECS and AWS Fargate Amazon ECR now supports exceptions to tag immutability (2025-07-23) Preventing image tags from being overwritten in Amazon ECR ECS タスク定矩 - linuxParameters KernelCapabilities - Amazon ECS Fargate security best practices in Amazon ECS Monitor Amazon ECS containers with ECS Exec (readonlyRootFilesystem ずの非互換に぀いお) Security hardening for GitHub Actions GHSA-mrrh-fwg8-r2c3: tj-actions/changed-files supply chain compromise CISA: Supply Chain Compromise of Third-Party tj-actions/changed-files (CVE-2025-30066) and reviewdog/action-setup (CVE-2025-30154) CVE-2024-3094: XZ Utils Backdoor Renovate Docker Presets Dependabot: Add digest pinning when updating Docker image tags (#14065 / PR #14071, 2026-02-04 マヌゞ枈み)