皆様ネットワーク運用自動化してますか? SSoT(Single Source of Truth)とは、「信頼できる唯一の情報源」を意味する概念です。 ネットワーク運用の文脈では、SSoTツールは以下のような役割を果たします: SSoTを導入することで、手動管理による情報の不整合や、複数の管理台帳が乱立する問題を解決できます。 ITインフラ本部ではPagodaというSSoTツールを内製開発しています。 前置きはこのくらいにして、本題である破壊の件について話していきます。 実は私は複数回SSoTツールを破壊しているのですが、それは全てREST API呼び出し時です。 一度目の破壊は、それまで以下のようにforループ内でrequestをしていたのですが、これを変更しようとした時です。 上記の例でloop_listの件数が増えるにつれて、ネットワークI/O待ちで処理時間がどんどん伸びていました。 これで何が起きるかと言いますと、listの要素数分のthreadを作成してほぼ同時にrequestsでHTTP Requestを行います。 この結果、成功するまで特に待機もなくHTTP Requestという名のDoS攻撃するコードに変貌してしまいました。 また、この経験から今後は気をつけようと思い、SSoTツール向けのRequestを代行するAdapter Serviceを作り、非同期関数にするついでにAsyncLimiterでRPSに制限をつけました。 上記の例の部分までは問題なかったのですが、FastAPIではuvicorn.runするときに、workersにてプロセス数を指定できます。 社内SSoTツールではRPSを40程度、のように緩く制限がされていたのですが、1コンテナの段階ですでに4倍の値となっています。 ちなみにworker数はk8sにDeployするなら1でコンテナ数のスケールで対応するべきです。その認識はあるのにAIによるVibeCodingで実装と開発環境へのDeployを行ったためSSoTツールが重たくなるまで気がついていませんでした。開発環境で動作確認と称して大量のRequestをAdapter Serviceに実行した際に上述の結果となりました。 これは過去動いていたツールを復旧させて欲しい、ということで対応していた際の話です。 変更時には特に意識せずにそのまま各コードを責任単位でコンテナ化してRedisにデータを保存、Redisにデータがなければ情報更新、数時間に1度cronjobにて全情報更新、というような形にしました。 この結果、検索条件のEndpointを複数回叩き、その結果に応じてさらにEndpointを叩く、というコードになっておりRequest数はもともと多く、仮でまずは動作するか見ようと上述のAdapter Service経由への変更を後にして復旧させました。その結果SSoTツールのAPIがまたまた高負荷となってしまい、cronjobの間隔と同じ間隔でWebUIの挙動が遅くなってしまいました。 これはツール作成時のメンバーがいなくなり、ドキュメントも特にないものを復旧させる、という作業内での出来事だったので大目に見て欲しい気持ちでいっぱいですが、上述のAIの生成したコードの件と同様にロジックまでは見ておくべきだったと反省しました。4敗です。 SSoTツールは全ての情報があるがゆえに、運用自動化をしようとするとそのAPIを叩く回数がどうしても増えて結果的に処理時間が長くなってしまい、力技で解決しようと雑に対応すると結果的にDoS攻撃になる、ということが今回の学びです。 ですが、やはり全ての情報が1箇所にあるというのはAPIの参照箇所も少なくて済み、その情報を正として扱って自動化できるため便利です。 Adapterの話をしているので、どこがどのように変わるのか示します。 ここまで4回のSSoTツール破壊事例を紹介しました。失敗を通じて学んだ重要なポイントは以下の3つです: SSoTツールは運用自動化の要です。これから自動化を進める方は、ぜひこれらの失敗から学んで、私のような轍を踏まないようにしてください! それでは、良い自動化ライフを!
はじめに
どうも、ITインフラ本部インフラ部ネットワークグループNREチームの佐々木です。
アドカレ12番目は社内SSoTツールを破壊してしまった話をしようと思います。SSoTとは?
システムやデータを管理する際に、情報を一箇所に集約し、その情報を正として扱うことで、データの整合性を保ち、管理の複雑さを軽減します。
利用しているSSoTツールについて
(参考: Pagoda デモサイトのリニューアルと今後の情報管理システムの展望 )
そのため、インフラ部ではこちらのツールをSSoTツールとして利用しています。
デモサイトなどもありますので、もし興味があればお問い合わせいただければと思います。どのように破壊したの?
1回目の破壊
import requests
loop_list = ["a", "b","c"]
for i in loop_list:
res = requests.get(f"http://example.jp/{i}")
そのため、以下のようにmulti threadにすれば良いと考えて実装しました。from concurrent.futures import ThreadPoolExecutor
import requests
def func(url):
res = requests.get(f"http://example.jp/{url}")
loop_list = ["a", "b","c"]
with ThreadPoolExecutor(max_workers=len(loop_list)) as executor:
for i in loop_list:
executor.submit(func, i)
そのため、list要素数が数千・数万になると当然、数千・数万のHTTP Requestがほぼ同時に発生します。
あくまで社内の人間が構成情報などの管理に使っているものなので、そこまでのRequestを想定しておらず、結果的にDoS攻撃のようになり構成管理ツールがダウンする事態になってしまいました。
さらに邪悪なことに、最初にダウンした際に何故かコードが失敗するな…と思い、以下のように関数を変更しました。def func(url):
while True:
res = requests.get(f"http://example.jp/{url}")
if res.status_code == 200:
break
もちろん、ダウンしている最中にはRequestが滞り、復旧と同時に再度攻撃に晒されてSSoTツールがダウンするという地獄の循環の出来上がりです。
取得しようとしているEntity/Entryからネットワークグループ由来として確認がきた際に気がつきました。
申し訳ない気持ちでいっぱいです。ここで1敗です。2回目の破壊
from aiolimiter import AsyncLimiter
rps_limit = 40
req_limiter = AsyncLimiter(rps_limit, 1)
async with req_limiter:
...
こちらの値を4などにしてPODとして動作させている時期があったため、4Process * 40limit * nコンテナ数 = 160nRPSという数値となっていました。uvicorn.run(
"main:app",
host="0.0.0.0",
port=5000,
reload=False,
workers=4
)
当然、想定していない同時Request数となるためその時も実質的にDoS攻撃となり、ダウンはしていないにしてもWebUI上で閲覧するにも検索に時間がかかる、といった状況となっていました。ここで2敗です。
これはこれでVibeCodingに丸投げしすぎという昨今の新しい課題な気がします。
AIが生成したコードの細部まで見るかはともかく、動作ロジックの部分は最低限見てPromptを与えた時の意図とズレていないかは確認すべきだなと感じました。ここで3敗です。3回目の破壊
全体像を見ると、JenkinsのビルドトリガーでPythonを起動し、SSoTツールから情報を取得してJSONファイルに保存、そのJSONをfrontendが読み込んで表示、という構成になっていました。これは現在のチーム方針であるマイクロサービスとしてk8s上でDeployがそのままでは難しいなと判断してアーキテクトの変更をしました。破壊して得た学び
おそらくバックエンドをメインで対応されている方からすると何を今更…という内容かもしれませんが、ITインフラ側のこれから運用自動化を進めたい!IaCやりたい!という方には参考になる内容かと思います。
また、最近話題になりがちなVibeCodingは、やはり100%丸投げできるものではなく、人間の指示以上の実装とはなりません。そのため、指示が雑な場合はReviewをしっかりしなくてはいけない、という点も学べました。
今後も懲りずにSSoTツールの利用をしていきたいと考えています。Adapterの簡略図
各PODが直接SSoTツールを叩いているとAPIのRPS制限への対応が難しくなりますが、Adapterを追加するとAdapterでRPSの制限を追加すれば問題ないため遵守しやすくなります。
また、仮にSSoTツールのFQDNに変更が走るなどしても、変更箇所はAdapterのみで済むために影響範囲を絞ることも可能です。
まとめ