ブログ

  • SLOを設定していないなら今すぐOpenTelemetryで計装しなさい

    「アラートが鳴り続けて疲弊している」「本番で問題が起きてもどこが原因かわからない」——これはオブザーバビリティ(可観測性)が不十分なシステムの典型的な症状です。メトリクス・ログ・トレースという「可観測性の三本柱」を統合的に扱う標準仕様として「OpenTelemetry(OTel)」が2024〜2025年にかけて事実上の業界標準となっています。

    オブザーバビリティをたとえで説明すると「飛行機のフライトレコーダー」のようなものです。何か問題が起きたとき、「いつ・どこで・何が起きたか」を後から正確に再現できる——これがオブザーバビリティの本質です。ログだけでは「何が起きたか」はわかっても「なぜ起きたか」はわかりません。トレースがあって初めて「リクエストがどのサービスのどの処理で遅くなったか」が見えます。

    運用エンジニアS:「注文APIのレスポンスが時々遅いんですが、ログを見てもどこで詰まってるかわからなくて」
    SREエンジニアT:「トレーシングが入ってないとそうなるよね。OpenTelemetryを計装すれば、リクエストが在庫サービス・決済サービス・配送サービスのどこで何ミリ秒かかったか全部見えるようになる」
    S:「大変な作業ですか?」
    T:「最近はゼロコード計装(auto-instrumentation)があるから、コードを一行も変えずに始められる」

    Node.jsアプリへのOpenTelemetry自動計装の例を見てみましょう。

    # 必要なパッケージをインストール
    npm install @opentelemetry/sdk-node \
      @opentelemetry/auto-instrumentations-node \
      @opentelemetry/exporter-otlp-grpc
    
    # tracing.js を作成
    # node --require ./tracing.js app.js で起動するだけでOK

    tracing.jsの中身はこうなります。

    const { NodeSDK } = require("@opentelemetry/sdk-node");
    const { getNodeAutoInstrumentations } = require("@opentelemetry/auto-instrumentations-node");
    const { OTLPTraceExporter } = require("@opentelemetry/exporter-otlp-grpc");
    
    const sdk = new NodeSDK({
      traceExporter: new OTLPTraceExporter({
        url: "http://otel-collector:4317",
      }),
      instrumentations: [getNodeAutoInstrumentations()],
    });
    
    sdk.start();

    次に、SLOの設定例をPrometheusのrecording ruleで定義してみましょう。

    # prometheus-rules.yaml
    groups:
      - name: slo_rules
        rules:
          # エラーレートの計算(99.9%の可用性SLO)
          - record: job:http_errors:rate5m
            expr: rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m])
          # SLOバジェット残量のアラート
          - alert: ErrorBudgetBurning
            expr: job:http_errors:rate5m > 0.001
            for: 5m
            labels:
              severity: warning

    「SLOを設定する」とは「このサービスはどの程度壊れていいか」を意識的に決めることです。99.9%の可用性なら年間8.7時間のダウンタイムが許容される——この「エラーバジェット」の考え方を持つことで、運用チームは「問題が起きるたびに全員が徹夜で対応する」という消耗から解放されます。今日からOpenTelemetryを入れて、まず可視化から始めましょう。見えないものは改善できません。

  • スケールしないMySQLを使い続けるくらいならNewSQLに乗り換えなさい

    「トランザクション処理はMySQLで、分析はBigQueryで、ってやってたら同期が大変になってきた」——データが増え、サービスがスケールするにつれてこの問題は必ず起きます。従来のRDBMSはスケールアウトが苦手で、シャーディングによる水平分割は複雑さを増します。この課題に対する答えのひとつが「NewSQL」というデータベースカテゴリです。

    NewSQLをたとえで説明すると「分散して働くのに、まるで一人の優秀な秘書のように振る舞うチーム」のようなものです。複数のサーバーにデータを分散させながら(スケールアウト)、SQLとACIDトランザクションという「使い慣れたインターフェース」を維持してくれる——それがNewSQLです。代表的なプロダクトはTiDB、CockroachDB、Google Spannerなどです。

    データエンジニアQ:「MySQLのシャーディングの管理がもう限界です。アプリ側でシャードキーを意識した実装が増えすぎて…」
    アーキテクトR:「TiDBを検討してみて。MySQLと互換性があるから、アプリコードをほぼ変えずに移行できる。水平スケールは自動でやってくれる」
    Q:「MySQLの構文がそのまま使えるんですか?」
    R:「ほぼね。MySQL 5.7互換のプロトコルで動くから、MySQLクライアントでそのまま繋げる」

    TiDBをDockerで試してみましょう。

    # TiUP(TiDBクラスタ管理ツール)のインストール
    curl --proto =https --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh
    
    # ローカルでTiDBクラスタを起動(開発用)
    tiup playground v7.5.0 --tag mytest
    
    # 別ターミナルでMySQLクライアントから接続(MySQLそのまま!)
    mysql -h 127.0.0.1 -P 4000 -u root

    次に、HTAPの特徴を活かすクエリ例を見てみましょう。TiDBはOLTP(トランザクション処理)とOLAP(分析処理)を同一クラスタで処理します。

    -- 通常のINSERT(OLTP)
    INSERT INTO orders (user_id, amount, created_at)
    VALUES (123, 9800, NOW());
    
    -- 同じクラスタで大規模な集計(OLAP)も可能
    SELECT DATE(created_at) as date,
           COUNT(*) as order_count,
           SUM(amount) as total_amount
    FROM orders
    WHERE created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)
    GROUP BY DATE(created_at)
    ORDER BY date;

    「MySQLを使い続けるか、NewSQLに移行するか」は、データ量・トラフィック・チームのスキルセットによります。しかしスケーラビリティの壁にぶつかってから慌てて移行するより、今のうちにNewSQLを触って選択肢として持っておくことが重要です。スケールしなくなったMySQLを使い続けることのリスクを、ぜひ一度真剣に考えてみてください。

  • AIワークロードを本番で捌きたいならGPUスケジューリングを理解しなさい

    「ChatGPTのようなAIモデルを自分たちのサーバーで動かしたい」——最近、このような相談が急増しています。しかしGPT-4クラスのモデルを動かすには、単純にGPUがあればいいというわけではなく、GPU間の通信帯域、分散学習の仕組み、バッチ処理の最適化など、専門的なインフラ知識が必要です。今回はAIワークロードのインフラ設計の基本を解説します。

    AIインフラをたとえで説明すると「高速道路の工場ライン」のようなものです。GPUは工員(処理担当)、VRAM(ビデオメモリ)は作業台の広さ、NVLink/InfiniBandはベルトコンベア(GPU間通信)です。作業台が狭い(VRAM不足)とモデルが乗り切らず、ベルトコンベアが遅い(通信帯域が細い)と工員が待ちぼうけになります。

    MLエンジニアO:「モデルの学習が遅すぎて困ってます。GPU使用率見たら30%しか使えてなくて…」
    インフラエンジニアP:「典型的なデータローディングのボトルネックだね。GPUが速すぎて、データが追いついてない状態。PyTorchのDataLoaderのworker数を増やしてみよう」
    O:「そんな設定があるんですね」
    P:「あと、混合精度演算(AMP)を有効にすれば学習速度が2倍近くになることもある」

    まず、GPUの利用状況を確認するコマンドです。

    # NVIDIA GPUの状態確認
    nvidia-smi
    
    # リアルタイム監視(1秒おきに更新)
    watch -n 1 nvidia-smi
    
    # GPU使用率・メモリ・温度を整形して表示
    nvidia-smi --query-gpu=name,utilization.gpu,memory.used,memory.total,temperature.gpu \
      --format=csv,noheader

    PyTorchで混合精度演算(AMP)を有効にする例です。

    import torch
    from torch.cuda.amp import autocast, GradScaler
    
    scaler = GradScaler()
    
    for batch in dataloader:
        optimizer.zero_grad()
        # AMPスコープ内でフォワードパス
        with autocast():
            output = model(batch)
            loss = criterion(output, target)
        # スケーラーでバックプロパゲーション
        scaler.scale(loss).backward()
        scaler.step(optimizer)
        scaler.update()

    Kubernetesでの推論サービングには、NVIDIA Triton Inference ServerやvLLMを使うのが現在のベストプラクティスです。vLLMはPagedAttentionという技術でVRAMの効率を大幅に改善し、LLMの推論スループットを数倍に向上させます。AIワークロードのインフラ設計は「GPUを積めば解決」ではありません。データパイプライン・通信帯域・スケジューリング・推論最適化——これらを組み合わせて初めて、GPUへの投資を最大化できます。

  • VPNをやめてゼロトラストに移行しなさい

    「社内ネットワークに入れば安全」——そんな時代は終わりました。リモートワークの普及、クラウドの多様化、SaaSの利用増加によって、もはや「社内と社外の境界」は意味をなさなくなっています。代わりに台頭してきたのが「ゼロトラスト(Zero Trust)」という考え方です。その名の通り「誰も・何も・最初から信頼しない」をセキュリティの原則とします。

    ゼロトラストをたとえで説明すると「厳格な入国審査」のようなものです。昔の国境管理は「一度入国した人は国内では自由に移動できる」というモデルでしたが、ゼロトラストは「空港に入るたびに、国内にいても、毎回パスポートと渡航目的を確認する」モデルです。一度認証されたからといって、ずっと信頼されるわけではありません。

    セキュリティ担当M:「VPNの維持コストとパフォーマンス問題で限界なんですよね。何かいい方法ないですか?」
    コンサルタントN:「ゼロトラストへの移行を検討してみてください。VPNをなくしてIDPとゼロトラストNAのような仕組みに移行している企業が増えてますよ」
    M:「コードや設定を全部見直すんですか?」
    N:「段階的にできます。まずIDプロバイダー(IdP)の強化と多要素認証(MFA)の徹底から始めましょう」

    ゼロトラストの実装ステップのひとつとして、mTLS(相互TLS)による通信の暗号化があります。opensslでクライアント証明書を作成する例を見てみましょう。

    # CA(認証局)の秘密鍵と証明書を作成
    openssl genrsa -out ca.key 4096
    openssl req -new -x509 -days 365 -key ca.key -out ca.crt \
      -subj "/CN=MyZeroTrustCA"
    
    # クライアント証明書の作成
    openssl genrsa -out client.key 2048
    openssl req -new -key client.key -out client.csr \
      -subj "/CN=my-service"
    openssl x509 -req -days 365 -in client.csr \
      -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt

    次に、OPAポリシーエンジンを使ったアクセス制御の例も見てみましょう。

    # OPA(Open Policy Agent)でアクセスポリシーを定義するRegoの例
    package httpapi.authz
    
    default allow = false
    
    # 管理者ロールを持つユーザーのみ /admin へのアクセスを許可
    allow {
      input.user.role == "admin"
      input.path == "/admin"
    }

    ゼロトラストへの移行は一夜にしてできるものではありませんが、「全通信の暗号化」「最小権限の原則」「継続的な認証」の3つを柱に、段階的に進めることができます。VPNは「城壁」でしたが、ゼロトラストは「すべての扉に鍵をかける」アプローチです。今すぐ完全移行は難しくても、MFAの徹底から始めましょう。

  • Kubernetesのクラウド費用を下げたいならFinOpsの習慣を身につけなさい

    「クラウドに移行したらコストが爆増した」——AWSやGCPを使い始めて半年後に多くの企業が直面する現実です。オンプレミスでは「ラックに入れたサーバーはもう払い済み」でしたが、クラウドは使った分だけ課金されます。特にKubernetesでリソースを過剰に確保(over-provisioning)していると、気づかないうちに莫大なコストがかかっています。これを解決するのが「FinOps」という考え方です。

    FinOpsをたとえで説明すると「電力の見える化と節電」のようなものです。家中の電気をつけっぱなしにしているのと同じで、使われていないリソースに課金され続けている——スマートメーターで電力消費を可視化して初めて「エアコンのつけっぱなし」に気づけるように、クラウドコストも「見える化」が第一歩です。

    コスト最適化担当K:「先月のAWS請求が先月比40%増になってるんだけど、何が増えたかわかる?」
    開発者L:「えっ、全然気づいてませんでした。どこで確認すればいいんですか?」
    K:「まずKubernetes側はkube-resource-reportかKubecostで見てみよう。どのPodがどれだけ無駄にCPU/メモリを確保してるか一発でわかる」

    まず現状のKubernetesリソース使用状況を確認しましょう。

    # 全Podのリソース実使用量を確認(metrics-serverが必要)
    kubectl top pods --all-namespaces --sort-by=memory
    
    # Nodeのリソース使用状況
    kubectl top nodes
    
    # Podのリソースリクエストと制限を一覧表示
    kubectl get pods --all-namespaces -o json | \
      jq -r '.items[] | [.metadata.namespace, .metadata.name, 
      (.spec.containers[].resources.requests.cpu // "未設定"), 
      (.spec.containers[].resources.requests.memory // "未設定")] | 
      @tsv'

    次に、コスト削減に有効な設定を見ていきましょう。使われていない時間帯にノードを自動スケールダウンするには、Cluster Autoscalerが有効です。

    # HPA(Horizontal Pod Autoscaler)の設定例
    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    metadata:
      name: my-app-hpa
    spec:
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: my-app
      minReplicas: 1
      maxReplicas: 10
      metrics:
      - type: Resource
        resource:
          name: cpu
          target:
            type: Utilization
            averageUtilization: 60

    さらに、スポットインスタンス(AWS)やプリエンプティブルVM(GCP)を活用することで、同等のスペックを最大70〜80%割引で利用できます。FinOpsは「ケチること」ではなく「必要な分だけ賢く使うこと」です。リソースを可視化し、無駄を削り、節約分を次の投資に回す——このサイクルこそがクラウドネイティブ時代のコスト管理の本質です。

  • エッジでコードを動かしたいならWebAssemblyを選びなさい

    「JavaScriptはブラウザで動くもの」——長い間そう思われていました。しかしWebAssembly(Wasm)の登場により、その常識は崩れつつあります。特にサーバーサイドやエッジでのWasm活用が2024〜2025年にかけて急速に広がっています。Wasmをブラウザの外で動かすための仕様「WASI(WebAssembly System Interface)」が整備され、コンテナの代替となりうる実行環境として注目されています。

    Wasmをたとえで説明すると「万能翻訳機を持つ旅行者」のようなものです。どの国(OS・CPU)に行っても、その場で最適な言語(機械語)に翻訳して話せる——つまり「Write Once, Run Anywhere」をコンテナよりも軽量に実現する技術です。起動時間はミリ秒以下、メモリフットプリントは数MBというケースも珍しくありません。

    新人エンジニアI:「エッジでコードを動かしたいんですが、Dockerコンテナだと重すぎて…」
    シニアエンジニアJ:「それ、Wasmが向いてるケースだよ。Wasmモジュールなら起動がコンテナの100倍速いこともある」
    I:「どんな言語で書けばいいんですか?」
    J:「RustかC/C++が一番相性いいけど、最近はGoやPythonもWasmにコンパイルできるよ」

    まずRustでシンプルなWasmモジュールを作ってみましょう。

    # Rustのインストール(未インストールの場合)
    curl --proto =https --tlsv1.2 -sSf https://sh.rustup.rs | sh
    
    # WASIターゲットを追加
    rustup target add wasm32-wasi
    
    # プロジェクト作成
    cargo new --bin hello-wasm
    cd hello-wasm

    src/main.rs に以下を書きます。

    fn main() {
        println!("Hello from WebAssembly!");
    }

    次にWasmにコンパイルして実行します。

    # WASIターゲットにコンパイル
    cargo build --target wasm32-wasi --release
    
    # wasmtimeランタイムでそのまま実行
    wasmtime target/wasm32-wasi/release/hello-wasm.wasm

    このwasmバイナリはLinuxでも macOSでもWindowsでも、wasmtimeさえあれば同じように動きます。さらにKubernetesでWasmを動かすための「Spin」(Fermyon製)や、Cloudflare Workersのようなエッジプラットフォームでも同じコードが動きます。コンテナよりも起動が速く、セキュリティサンドボックスが強固なWasm——次世代のサーバーサイド実行環境として、今から触っておく価値は十分あります。

  • 開発者に何度も同じ質問をさせたくないなら内部開発者プラットフォームを作りなさい

    「デプロイするにはどうすればいいですか?」「ステージング環境のURLは?」——毎日同じ質問をSlackで受け続けているインフラ担当者はいませんか?これは個人の問題ではなく、組織の構造的問題です。解決策は「内部開発者プラットフォーム(IDP:Internal Developer Platform)」の構築、いわゆるPlatform Engineeringの実践です。

    IDPをたとえで説明すると「セルフサービスのコンビニ」のようなものです。以前は「店員(インフラチーム)に声をかけて商品を取ってきてもらう」スタイルだったのが、「棚に商品が並んでいて、自分で取れる」スタイルに変わります。開発者が必要なインフラやツールに自分でアクセスでき、インフラチームへの依存を減らせます。

    新人エンジニアG:「新しいサービスを立ち上げたいんですが、まず何から始めればいいですか?」
    プラットフォームエンジニアH:「IDPのポータル開いて、新規サービス作成を押すだけだよ。GitHubリポジトリ・CI/CDパイプライン・Kubernetesのnamespace・監視設定——全部自動でセットアップされる」
    G:「え、それだけですか?」
    H:「それだけ。僕らはその『それだけ』を作るのに3ヶ月かけたんだけどね」

    IDPの代表的なOSSとして「Backstage」(Spotifyが開発)があります。まず手元で試してみましょう。

    npx @backstage/create-app@latest
    cd my-backstage-app
    yarn dev

    起動すると http://localhost:3000 でBackstageのポータルが開きます。ここにサービスカタログ・TechDocs・テンプレート(Scaffolderと呼ぶ)を追加していくことで、開発者が自走できる環境が整っていきます。

    Platform Engineeringの本質は「インフラチームが開発者の代わりに作業する」のではなく「インフラチームが開発者が自走できるプラットフォームを作る」という役割の転換です。繰り返す質問がなくなれば、インフラチームはより本質的な課題に集中できます。今日から「自分たちのIDPに何を載せるか」を考えてみましょう。

  • Linuxカーネルを触らずに拡張したいならeBPFを使いなさい

    「カーネルモジュールを書いてカーネルを拡張したい、でもカーネルをクラッシュさせるリスクが怖い」——かつてはそんなジレンマがありました。しかし今、eBPF(extended Berkeley Packet Filter)という技術がそのジレンマを解消しています。eBPFを使えば、Linuxカーネルのソースコードを変更することなく、カーネル内でプログラムを安全に実行できます。2024年〜2025年にかけて、可観測性・セキュリティ・ネットワーク分野での採用が急拡大しています。

    eBPFをたとえで説明すると「原子力発電所の制御室にある監視カメラ」のようなものです。原子炉の内部に直接手を入れることなく、すべての動きをリアルタイムで観測し、必要なら介入できる——しかもカーネル自体の安定性は損なわない。これがeBPFの本質です。

    新人エンジニアE:「本番サーバーでネットワークの遅延が発生してるんですが、strace使うとオーバーヘッドが大きすぎて…」
    シニアエンジニアF:「eBPFベースのbccツールを使えばほぼオーバーヘッドゼロで調査できる。tcptracer試してみよう」
    E:「カーネルを再コンパイルしなくていいんですか?」
    F:「必要なし。動いてるカーネルにそのまま注入できる。それがeBPFの強みだよ」

    eBPFを手軽に体験するには「bcc」または「bpftrace」が便利です。まずインストールしてみましょう(Ubuntu/Debian系の場合)。

    sudo apt-get install -y bpftrace
    
    # 全システムコールをトレース(誰が何をしているか観測)
    sudo bpftrace -e 'tracepoint:syscalls:sys_enter_* { @[probe] = count(); }'
    
    # 5秒間のTCP接続をリアルタイムで確認
    sudo bpftrace -e 'kprobe:tcp_connect { printf("%s -> connect\n", comm); }'

    さらに実践的な例として、特定プロセスのディスクI/Oレイテンシを計測してみましょう。

    # biolatency: ブロックI/Oのレイテンシ分布を表示(bccツール)
    sudo /usr/share/bcc/tools/biolatency -D 10
    
    # execsnoop: 新しいプロセス起動をリアルタイム監視
    sudo /usr/share/bcc/tools/execsnoop

    eBPFの応用範囲は非常に広く、CiliumはeBPFベースのKubernetesネットワーキング(CNI)として注目されており、FalcoやTetragonはeBPFでコンテナのランタイムセキュリティを実現しています。また、MetaやGoogle、Cloudflareといった大手企業がeBPFを本番環境の中核技術として採用しています。カーネルを壊さずにカーネルを拡張できる——eBPFはLinux運用の常識を変えつつある技術です。ぜひ手元の環境で動かしてみてください。

  • マイクロサービスの通信管理はIstioに任せなさい

    「マイクロサービス、便利そうだから導入してみたら、サービス間の通信の管理が地獄になった」——こんな声をよく聞きます。サービスが10個、20個と増えていくと、「AがBに通信できるか」「通信が失敗したときのリトライはどうするか」「どのサービスがボトルネックか」を管理するのが急に難しくなります。これを解決するのがサービスメッシュ、そして代表的なツールが「Istio」です。

    サービスメッシュをたとえで説明すると「交通整理の警官」のようなものです。車(リクエスト)がどこから来て、どこへ向かい、渋滞(レイテンシ)はどこで起きているか——これをすべて把握して制御する存在です。アプリケーションのコードを一切変えずに、通信ルール・リトライ・タイムアウト・暗号化(mTLS)を外から注入できるのがIstioの最大の魅力です。

    新人エンジニアC:「サービスAからサービスBへのリクエストが時々タイムアウトするんですが、原因がわからなくて…」
    シニアエンジニアD:「Istioのダッシュボード(Kiali)で通信フローを見てみよう。どのサービスがどこに通信してるか一目でわかるよ」
    C:「え、コードに何も書かなくていいんですか?」
    D:「Istioがサイドカーコンテナとして通信をすべて横取りしてくれるから、アプリは何も意識しなくていい」

    IstioをKubernetesクラスターにインストールするにはistioctl(公式CLIツール)を使います。

    # istioctlのダウンロードとインストール
    curl -L https://istio.io/downloadIstio | sh -
    cd istio-1.x.x
    export PATH=$PWD/bin:$PATH
    
    # クラスターへのインストール(デモプロファイルで試す場合)
    istioctl install --set profile=demo -y
    
    # 名前空間にIstioサイドカー自動注入を有効化
    kubectl label namespace default istio-injection=enabled

    これだけで、defaultネームスペースにデプロイされるすべてのPodに「Envoyプロキシ」がサイドカーとして自動注入されます。アプリケーション間のすべての通信がこのプロキシを経由するようになります。

    次に、たとえばサービスAからサービスBへの通信が失敗したとき、3回まで自動でリトライするルールをYAMLで定義してみましょう。

    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: service-b
    spec:
      hosts:
      - service-b
      http:
      - retries:
          attempts: 3
          perTryTimeout: 2s
        timeout: 10s
        route:
        - destination:
            host: service-b

    このYAMLをapplyするだけで、コードを一行も変えることなくリトライとタイムアウトが設定できます。「交通整理の警官」が「3回まで迂回路を試してから諦める」ルールを持つようになったイメージです。サービスが増えるほどIstioの恩恵は大きくなります。マイクロサービス化を進めるなら、早めにサービスメッシュの導入を検討しましょう。

  • Dockerイメージを本番に持ち込む前に必ずTrivyでスキャンしなさい

    「Dockerで本番環境に上げたら、突然セキュリティアラートが大量に出て大騒ぎになった」——そんな経験をしたエンジニアは少なくないはずです。コンテナは便利な反面、ベースイメージの中に古いライブラリや既知の脆弱性が潜んでいることがあります。そこで今回は、無料で使えるコンテナ脆弱性スキャナー「Trivy」を使って、本番投入前に問題を検出する方法を解説します。

    まず「なぜスキャンが必要なのか」を、身近なたとえで考えてみましょう。Dockerイメージは「冷凍食品」のようなものです。中に何が入っているか、パッケージを開けてみないとわからない——いや、もっと正確に言えば「成分表示を読まないと危険なものが混入していても気づかない」のです。nginx:latestというイメージを何も確認せずに使うのは、賞味期限も原材料も確認せずに冷凍食品を食べるようなもの。Trivyはその「成分表示をくまなく読んでくれるツール」です。

    実際の現場でよくある会話を再現してみましょう。

    新人エンジニアA:「このDockerイメージ、公式のubuntu:20.04をベースにしてるから安全ですよね?」
    ベテランエンジニアB:「公式だから安全、ってわけじゃないんだよ。公式イメージでも古いOpenSSLや既知CVEを含んでることがある。スキャンした?」
    A:「え、スキャンするんですか?」
    B:「当然。Trivyで10秒もあればわかる。やってみせるよ」

    Trivyのインストールと基本的な使い方は非常にシンプルです。まずインストールから始めましょう(macOSの場合)。

    brew install trivy

    インストールが完了したら、Dockerイメージをスキャンしてみましょう。たとえばnginxの公式イメージを対象にする場合はこうなります。

    trivy image nginx:latest

    実行すると、CVE番号・深刻度(CRITICAL/HIGH/MEDIUM/LOW)・修正バージョンの一覧が出力されます。深刻度CRITICALやHIGHの脆弱性が含まれる場合は、ベースイメージをより新しいバージョンや軽量な「distroless」イメージに切り替えることを検討しましょう。

    さらに一歩進んで、CI/CDパイプライン(GitHub Actionsなど)にTrivyを組み込むと、Pull Request時に自動でスキャンが走り、CRITICALが検出されたらマージをブロックする運用が実現できます。設定例はこちらです。

    - name: Run Trivy vulnerability scanner
      uses: aquasecurity/trivy-action@master
      with:
        image-ref: 'myapp:latest'
        format: 'table'
        exit-code: '1'
        severity: 'CRITICAL,HIGH'

    「exit-code: 1」の設定がポイントで、CRITICALまたはHIGHの脆弱性が見つかったときにCIを失敗させることができます。セキュリティは後回しにするほどコストが跳ね上がります。今日からTrivyをパイプラインに組み込む習慣をつけましょう。