Ubuntu - TECH PLAY - TECH PLAY

TECH PLAY

Ubuntu

イベント

該当するコンテンツが見つかりませんでした

マガジン

該当するコンテンツが見つかりませんでした

技術ブログ

本ブログは 2026 年 10 月 14 日に公開された AWS Blog “ Penetration testing every deployment with AWS Continuum ” を翻訳したものです。 静的解析 (SAST)、ソフトウェア構成分析 (SCA)、動的スキャナー (DAST) など、CI/CD パイプラインに組み込めるセキュリティツールの多くは、パターンやシグネチャに基づいて 潜在的な 問題にフラグを立てます。フラグが立てられたパターンは調査すべき箇所を示しますが、実際に悪用可能かどうかを確認するのはペネトレーションテストの役割です。従来、この確認は、デプロイのたびではなく、スケジュールに沿って定期的に実施される、パイプラインとは別枠の診断によって行われてきました。そのため、診断と診断の間に行われたデプロイは、確認が済まないまま本番環境に到達していました。 AWS Continuum for penetration testing (旧称 AWS Security Agent) は、AI エージェントを使用して、実行中のアプリケーションに存在する悪用可能な脆弱性を検出し、確認するサービスです。この記事では、このサービスをパイプラインのデプロイ後ゲートとして組み込む方法を説明します。このゲートは、 直前にデプロイした変更に自動的にスコープを限定した ペネトレーションテストを実行し、検出結果の重要度が指定したしきい値以上の場合は、本番環境への昇格をブロックできます。各実行では、アプリケーション全体ではなく、前回ゲートを通過して以降の変更のみをテストするため、デプロイのたびに実行できるほど高速かつ経済的です。この記事では、主要な 4 つの CI/CD プラットフォーム (GitHub Actions、GitLab CI/CD、Bitbucket Pipelines、Azure DevOps Pipelines) に適用できるこのパターンの概要を説明したうえで、GitHub Actions を使用した具体的な例を紹介します。 この記事を読み終えるころには、変更をステージング環境にデプロイし、デプロイした変更に対してスコープを限定したペネトレーションテストを実行して、ゲートを通過した場合にのみ変更を本番環境に昇格させるパイプラインが完成します。 次の図は、エンドツーエンドのフローを示しています。CI/CD パイプラインがステージング環境にデプロイすると、ペネトレーションテストゲートのステップが OpenID Connect (OIDC) を使用して AWS アカウントに対して認証し、Continuum for penetration testing を呼び出します。Continuum for penetration testing は、ステージング環境に対してスコープを限定したテストを実行します。ゲートは結果を待ってパイプラインに報告し、結果に応じて本番環境への昇格をブロックします。テストはすべて AWS アカウント内のサーバー側で実行されるため、CI/CD ランナー上でペネトレーションテストのロジックが実行されることはありません。 図 1: パイプラインゲートのアーキテクチャ: CI/CD パイプラインがステージング環境にデプロイし、ペネトレーションテストゲートが OIDC で認証して Continuum for penetration testing を呼び出します。Continuum for penetration testing は、本番環境への昇格可否を左右するスコープ判定を返します。 変更にスコープを限定することが重要な理由 ゲートをデプロイのたびに実行できるのは、各テストのスコープを直前にデプロイした変更に限定しているためです。Continuum for penetration testing はコミット範囲を決定し ( head はゲートの対象となるコミット、 base はゲートが前回通過を認めたコミットです)、変更された部分のみをテストします。アプリケーション全体ではなく変更をテストすることで、デプロイごとのペネトレーションテストを、四半期ごとの定期作業ではなくパイプラインに組み込めるほど短時間かつ低コストで実行できます。 各実行では、3 つのスコープ判定のいずれかが返されます。具体的には、 in scope (スコープ内: 変更によってアタックサーフェスが変化しており、検出結果がしきい値に基づいて評価されます)、 scoped out (テスト不要: 変更はスコープ内ですが、セキュリティに関係する変更がないため、パイプラインは通過します)、 scope conflict (スコープの競合: 変更が設定済みのスコープ外にあるためテストされておらず、これをブロック対象にするかどうかを選択できます) です。Continuum for penetration testing コンソールでは、各実行の [Scoping] タブに判定結果とコミット範囲が記録されます。そのため、ゲートがブロックした場合は、その理由を正確に確認できます。コミット範囲の計算方法と検証方法の詳しい仕組みについては、「 How the pipeline integration scopes the test 」を参照してください。 ゲートは、パターンマッチではなく、Continuum for penetration testing が悪用可能であると検証した検出結果に基づいてブロックします。そのため、パイプラインが赤 (失敗) になった場合の意味は明確です。つまり、変更に再現可能な脆弱性が存在し、昇格前に修正が必要だということです。 ゲートのセットアップ ゲートのセットアップは 3 つのステップで完了します。ペネトレーションテストの設定、パイプラインが引き受け可能な AWS Identity and Access Management (IAM) ロールの作成、パイプラインへのゲートステップの追加です。 開始する前に、IAM OIDC ID プロバイダーと IAM ロールの両方を作成するアクセス許可を持つ AWS アカウントと、ペネトレーションテストから到達可能なステージング環境を用意してください。 ステップ 1: ペネトレーションテストを設定する 「 Before you start 」の説明に従って、1 回限りのセットアップを完了します。具体的には、ターゲットドメインを検証し、Agent Space でペネトレーションテストを作成し、CI/CD モードを有効にして、リポジトリを接続します。Agent Space ID (as-…) とペネトレーションテスト ID (pt-…) は、ステップ 3 でゲートステップに渡すため、控えておいてください。パイプラインがテストするのは、このペネトレーションテストで設定された対象です。そのため、ゲートがカバーする範囲は、このペネトレーションテストのターゲットとスコープによって決まります。 ステップ 2: IAM ロールを作成する 認証には、保存したキーではなく OIDC フェデレーションを使用します。CI/CD プロバイダーがパイプラインを識別する有効期間の短いトークンを発行し、事前に作成した IAM ロールをパイプラインが引き受ける際に、 AWS Security Token Service (AWS STS) がそのトークンを一時的な認証情報と交換します。長期間有効な AWS アクセスキーを CI/CD 変数として保存する必要がないため、パイプラインから漏えいすることが最も多い認証情報をなくすことができます。 ゲートのセキュリティは、IAM ロールの 2 つのポリシーに依存します。 信頼ポリシー (どのパイプラインがロールを引き受けられるか) と アクセス許可ポリシー (ロールを引き受けた後にパイプラインが実行できる操作) です。正確なポリシー JSON、プロバイダー固有の OIDC URL と audience の値、各 CI/CD プラットフォームの sub クレームの形式については、「 Scope the trust policy to your pipeline 」と「 Grant least-privilege permissions 」のリファレンスに従ってください。 これらのポリシーのスコープを決める際の判断ポイントを次に示します。 最初に判断するのは、 信頼ポリシーのスコープをどこまで厳密にするか です。このパイプラインでデプロイするブランチが 1 つだけであれば、 sub クレームをそのブランチ (例えば、 main ) に固定するのが適切なデフォルトです。複数のブランチや環境で正当にゲートを実行する場合は、プロバイダーのクレームが対応していれば、ブランチではなく環境単位でスコープを限定してください。なお、すべてのプロバイダーがクレームにブランチを含めるわけではない点に注意してください。Bitbucket では、リポジトリ (およびオプションでデプロイ環境) が最も厳密なスコープとなります。まずは実際のデプロイ状況が許す限り狭い範囲から始め、実際のブランチや環境で必要になった場合にのみ範囲を広げてください。また、2026 年 7 月 15 日以降に作成または名前変更された GitHub リポジトリは、数値 ID を含むイミュータブルな sub クレームを発行します。ポリシーを作成する前に、パイプラインが実際に発行する sub を確認してください。 ステップ 3: パイプラインにゲートステップを追加する ステップの考え方はどのプロバイダーでも同じで、異なるのは構文だけです。アップストリームの変更によってパイプラインで実行される内容が変わらないよう、インテグレーションはイミュータブルなバージョン (リリースタグ、コミット SHA、または固定したコンポーネントバージョン) に固定してください。設定の完全なリファレンスとデフォルト値の一覧については、「 Defaults the integration ships with 」を参照してください。 ゲートを本格的に運用する前に、 ドライランモード で一度実行してください。ドライランでは、スコープを限定したペネトレーションテストのジョブを開始することなく、認証が成功すること、リージョンの指定が正しいこと、および対象のリポジトリを正しく特定できることを確認します。検証に失敗した場合は、エラー処理の設定にかかわらずステップが失敗するため、設定ミスにすぐ気付くことができます。 具体的な例: GitHub Actions 次のワークフローは、ゲートを機能させるための 3 つのジョブ構成を示しています。 deploy はステージング環境へのデプロイ、 security-pentest はゲートの実行、 deploy-prod は本番環境への昇格を担当します。 deploy-prod は needs: [security-pentest] を宣言しているため、ゲートが失敗すると GitHub は本番環境へのデプロイをスキップします。 注: チュートリアルでは、ゲートがブロックする実際の検出結果を得るために、意図的に SQL インジェクションの脆弱性を含めたアプリケーションを使用しています。このアプリケーションは、隔離された非本番環境にのみデプロイし、作業が終わったら削除してください。 jobs: deploy: runs-on: ubuntu-latest environment: staging steps: - uses: actions/checkout@v4 with: persist-credentials: false - run: ./deploy.sh staging security-pentest: needs: [deploy] runs-on: ubuntu-latest permissions: id-token: write contents: write actions: read deployments: read steps: - uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::111122223333:role/my-pentest-gate-role aws-region: us-west-2 role-duration-seconds: 7200 - uses: aws-actions/aws-continuum-run-pentest@v1 with: agent-space-id: as-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx pentest-id: pt-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx severity-threshold: HIGH on-scope-conflict: block timeout-minutes: "45" deploy-prod: needs: [security-pentest] runs-on: ubuntu-latest environment: production steps: - uses: actions/checkout@v4 with: persist-credentials: false - run: ./deploy.sh production アカウント ID、ロール名、リージョン、 as-/pt- 識別子は、実際の値に置き換えてください。 この例では、2 つの点に注意してください。まず、 contents: write アクセス許可によって、ゲートはリポジトリ内に ref として保持している ベースラインマーカーを進める ことができます。書き込みアクセス権がないと、毎回の実行で意図よりも広い範囲がテストされてしまいます。次に、認証情報ステップの role-duration-seconds: 7200 は、ペネトレーションテストの所要時間より長くする必要があります。ロールで許可されている上限を超える期間をリクエストすると、AWS STS は期間を短縮するのではなくリクエストを拒否します。そのため、ロールの最大セッション期間は少なくとも (タイムアウト + 10) x 60 秒に設定してください。途中で認証情報の有効期限が切れると、本来は正常な実行が、あたかもサービス側に問題があるかのように失敗します。さらに、クリーンアップ処理も、取り残されて実行を続けているジョブを停止できなくなります。 4 つのプロバイダーすべてについて、詳細な手順を解説したチュートリアルへのリンクをこの記事の最後に掲載しています。 ゲートのロールアウト: レポート専用モードからブロック運用へ ロールアウトの前に、最も重要なポイントを押さえておきましょう。 ステップが失敗するかどうかは 3 つの独立した設定によって決まり、それぞれ異なる結果を対象としています。 severity-threshold (検出結果の扱い)、 on-scope-conflict (変更がテストされなかった場合の扱い)、 fail-on-infrastructure-error (ジョブを実行できなかった場合の扱い) です。これらは互いに独立しているため、1 つを緩和しても他の設定には影響しません。 多くのチームは、まず レポート専用モード でゲートを導入します。しきい値を NONE に設定すると、テストは実行されて検出結果も報告されますが、パイプラインはブロックされません。1~2 回のリリースで検出内容を確認してから、しきい値を HIGH に変更して、判定を厳しくします。この段階的なロールアウトは妥当な方法ですが、 重要な注意点が 1 つあります。 ゲートを通過した実行は、レポート専用モードでの実行も含めて、ベースラインを進めます。 その実行の範囲に含まれるコミットは通過済みとして記録されるため、後でしきい値を厳しくしても 再テストされません 。例えば、1 か月間レポート専用モードで運用した後に HIGH に切り替えた場合、ゲートが評価するのは最後のレポート専用モードでの実行 以降 のコミットのみです。既にレポート済みの内容まで遡って再チェックすることはありません。 これは設計上の動作です。設定を緩和するということは、その設定で許容される結果を受け入れることを意味します。ただし、以前の実行で通過済みとなった範囲を、より厳しい設定で再評価したい場合は、 head と base のコミット SHA をオーバーライドしてください。具体的には、 base-commit-sha と head-commit-sha を設定します。マーカーの保存場所はプロバイダーによって異なります。プロバイダーごとの対応表については、「 What advances the baseline, and why that matters 」を参照してください。 また、注意すべきデフォルト値も 1 つあります。 fail-on-infrastructure-error のデフォルト値は false (フェイルオープン) です。昇格にセキュリティ承認が必要なパイプラインでは、最初から true に設定してください。 GitLab: コミットした設定はデフォルト値にすぎず、保証ではない GitLab CI/CD では、パイプライン変数が、ジョブ自身の variables: ブロックで設定された値よりも優先されます。つまり、パイプラインを実行できるユーザーであれば誰でも、しきい値を下げる、ドライランを有効にする、エラー処理を緩和するといった変数を指定できてしまいます。その場合、ゲートは .gitlab-ci.yml の記述ではなく、変数の指定どおりに動作します。リリースを止める役割をゲートに任せる前に、プロジェクトの CI/CD 設定で、変数をオーバーライドできるユーザーを制限してください。 ランナー上の認証情報の保護 ステップの実行中は、一時的な認証情報と OIDC トークンを機密情報として扱う必要があります。次の 3 つの対策が重要です。 デバッグと詳細トレースを無効にしておく : 認証情報を扱うステップが対象です。シェルのトレースモード (例えば、GitLab CI の CI_DEBUG_TRACE ) は、コマンド引数を平文でジョブログに出力します。 ソース管理の認証情報をワークスペースに残さない : チェックアウトステップで persist-credentials: false を設定し、後続のステップから読み取れるランナーの .git 設定にトークンが書き込まれないようにします。 信頼できないステップにトークンを公開しない : OIDC トークンのアクセス許可は必要なジョブにのみ付与し、トークンを読み取れるジョブでは信頼できないコード (フォークのビルドなど) を実行しないようにします。 本番環境とマルチアカウント構成への適用 この例では、わかりやすくするために 1 つのアカウントを使用しています。実際には、ステージング環境と本番環境を別々の AWS アカウントに分けることも多いでしょう。その場合も、このパターンは次のように無理なく拡張できます。 ペネトレーションテストゲート用の IAM ロールは、ペネトレーションテストと Agent Space が存在するアカウント (セキュリティアカウント) に作成します。パイプラインは、どのワークロードアカウントにデプロイする場合でも OIDC を介してこのロールを引き受けます。そのため、各アカウントにロールのコピーや長期間有効なキーを置く必要がなく、適切にスコープを設定した 1 つのゲートロールを維持するだけで済みます。 昇格の経路にある本番前の各環境に対してゲートを実行し、その結果に基づいて次のステージへの昇格を制御します。ベースラインはゲートを通過した場合にのみ進むため、デプロイをまたいでもカバレッジが途切れることはありません。 ゲートが実際のリリースを止める役割を担うようになったら、 fail-on-infrastructure-error を true に設定し、パイプライン変数をオーバーライドできるユーザーを制限します。 アップストリームの変更が実行前にレビューされるよう、インテグレーションのバージョンを固定します。 AWS Security Agent に関するより幅広いガイダンス (非本番環境に対するテスト、AI が生成した検出結果の検証、IAM など) については、「 Security best practices for AWS Continuum 」を参照してください。 クリーンアップ ゲートを試すためにいずれかのプロバイダー向けチュートリアルを実施した場合は、そのチュートリアルの「 Clean up 」セクションの手順に従って、作成したリソースをすべて削除してください。対象は、サンプルアプリケーションのステージング環境、IAM ロールと OIDC ID プロバイダー、そして (ウォークスルー専用に作成した場合は) Continuum for penetration testing コンソールのペネトレーションテスト (および専用の Agent Space) です。これらを削除することで、継続的な料金の発生を防ぎ、意図的に脆弱性を含めたサンプルアプリケーションをオフラインにできます。 まとめ ペネトレーションテストのスコープをデプロイした変更に限定することで、四半期ごとの取り組みではなく、デプロイごとのゲートとしてペネトレーションテストを実用的に運用できるようになります。押さえておくべき重要な判断は次のとおりです。 厳格さ : レポート専用モード ( NONE ) から始めます。ただし、ベースラインが進む点に注意し、しきい値を厳しくする際にはマーカーを削除してください。 失敗時の動作 : セキュリティ承認が必要なものについては、 fail-on-infrastructure-error を true に設定します。 信頼のスコープ : sub クレームは、実際のデプロイ状況が許す限り狭く固定します。 ロールの配置場所 : セキュリティアカウントに 1 つのロールを配置し、各ワークロードのパイプラインから OIDC を介して引き受けます。 お使いのプラットフォームでゲートをエンドツーエンドで構築するには、プロバイダーに対応するチュートリアルを参照してください。 Tutorial: Gate a GitHub Actions deployment with a scoped penetration test Tutorial: Gate a GitLab CI/CD deployment with a scoped penetration test Tutorial: Gate a Bitbucket Pipelines deployment with a scoped penetration test Tutorial: Gate an Azure DevOps deployment with a scoped penetration test 概念の説明と完全なリファレンスについては、「 Run penetration tests from your CI/CD pipeline 」を参照してください。 Jigar Bhatt Jigar は AWS Continuum for Penetration Testing のシニアソフトウェアエンジニアです。AI を活用したペネトレーションテスト機能を開発し、お客様がアプリケーション内の悪用可能な脆弱性を検出して修正できるよう支援しています。AI セキュリティの分野に携わる前は、AWS CodeBuild で数年間にわたり開発者ツールの構築に従事していました。インドの BITS Pilani でソフトウェアシステムの工学修士号を取得しています。 Benjamin Li Benjamin は AWS Continuum for Penetration Testing チームのソフトウェアエンジニアで、AI を活用したペネトレーションテスト機能を開発しています。UW で数学の学士号を取得しました。 本ブログは Security Solutions Architect の 中島 章博 が翻訳しました。
はじめに Kubernetes上でLLMの推論などGPUを使うワークロードを動かすには、GPUノードにドライバを入れ、PodからGPUを利用できる状態にしておく必要があります。本記事では、インターネットに接続できないAirGap環境のRKE2クラスタに対して、NVIDIA GPU DriverとNVIDIA GPU Operatorを導入し、Kubernetes上でGPUを使えるようにするまでの手順を紹介します。 SUSE AIのようなKubernetes上のAI基盤を構築する際の前提作業にあたりますが、手順自体は特定のAI基盤に依存しない汎用的な内容です。RKE2以外のKubernetesディストリビューションでも、containerdのソケットや設定ファイルのパスを読み替えれば応用できます。 GPU設定に必要なツール KubernetesでGPUを使うには、ノードのOS側でGPUを動かす「NVIDIA GPU Driver」と、Kubernetes側でGPUをリソースとして扱うためのコンポーネント群をまとめて管理する「NVIDIA GPU Operator」の2つが必要です。 NVIDIA GPU Driver NVIDIA GPU Driverは、OSがGPUを認識・制御するためのソフトウェアです。カーネルモジュール( nvidia 、 nvidia_uvm など)と、 libnvidia-ml.so や libcuda.so といったユーザー空間ライブラリ、 nvidia-smi などの管理ツールで構成されます。コンテナ内のCUDAアプリケーションも、最終的にはホスト上のこのドライバを経由してGPUを利用します。 Kubernetesで使う場合、ドライバの導入方法は次の2通りです。 ホストOSに直接インストールする :OSのパッケージ管理でドライバを入れる方法です。 GPU Operatorのドライバコンテナで入れる :GPU Operatorがドライバ入りのコンテナを各ノードで動かし、カーネルモジュールをロードする方法です。 ホストOSに直接インストールする方法はドライバをOSのパッケージ管理で扱えるため、OSの更新やイメージ管理とあわせてドライバを管理したい場合に向いています。また、Kubernetes以外のプロセスからもGPUを使いやすくなります。 GPU Operatorのドライバコンテナで入れる方法は、OperatorがすべてのGPUノードにドライバを自動で導入し、更新も管理するため、GPUノードが多い場合や頻繁に増減する場合に向いています。 本記事では前者のホストOSへの直接インストールの手順を解説します。 なお、ドライバのバージョンはGPU Operatorのサポート対象から選びます( Release Notes )。 NVIDIA GPU Operator NVIDIA GPU Operatorは、KubernetesでGPUを使うために必要なNVIDIAのソフトウェア一式を、Operatorパターンで自動的にデプロイ・管理する仕組みです。本来はノードごとに個別に設定する必要があるコンテナランタイムの設定やDevice Pluginなどを、 ClusterPolicy というカスタムリソースでまとめて宣言的に管理できます。 出典: About the NVIDIA GPU Operator GPU Operatorが管理する主なコンポーネントと、本記事での扱いは次のとおりです。 コンポーネント 役割 本記事での扱い Node Feature Discovery(NFD) ノードのハードウェア情報を検出し、NVIDIA GPU搭載ノードにラベルを付与 有効 GPU Feature Discovery(GFD) GPUの型番・メモリ量・ドライババージョンなどを nvidia.com/* ラベルとして付与 有効 NVIDIA Container Toolkit コンテナランタイム(containerd)を設定し、コンテナからGPUを使えるようにする 有効 NVIDIA Device Plugin GPUを拡張リソース nvidia.com/gpu としてkubeletに登録し、Podへ割り当てる 有効(タイムスライシング設定あり) DCGM Exporter GPUの使用率や温度などのメトリクスをPrometheus形式で公開 有効 Operator Validator ドライバ・Toolkit・Device Pluginが正しく動作しているか検証 有効 NVIDIA Driver(コンテナ) ドライバをコンテナとして導入 無効(ホストに導入済みのため) MIG Manager MIG対応GPUの分割構成を管理 無効(MIG非対応のGPUノードを使うため) 設定手順 設定概要 AirGap環境では、インターネットに接続できる作業用端末で必要な資材を集め、閉域側のノードやレジストリへ運び込んでから設定します。全体の流れは次のとおりです。 作業用端末でNVIDIA GPU Driverのパッケージ(.deb)をダウンロードし、GPUノードへ転送する GPUノードにNVIDIA GPU Driverをインストールし、動作を確認する 必要に応じてGPUノードにラベルとテイントを設定する 作業用端末でGPU OperatorのHelmチャートとコンテナイメージを取得し、閉域内のHelmリポジトリ・コンテナレジストリへ登録する RKE2のHelmChartリソースでGPU OperatorをDownstream Clusterにインストールし、動作を確認する インターネットに接続できるのは作業用端末だけです。Downstream Clusterは、閉域内のHarborからチャートとイメージを取得します。 前提条件 GPUノードのOSが、NVIDIA GPU DriverとGPU Operatorのサポート対象であること( Platform Support ) SUSE Rancher PrimeのRancher Management Server(以下、RMS)と、RMSから管理されるRKE2のDownstream Clusterが構築済みであること RMSとDownstream ClusterはAirGap環境にあり、インターネットに接続できないこと Downstream ClusterのRKE2がcontainerd 2.x系を同梱していること(GPU Operator v25.10以降のCDIを使う前提) インターネットに接続できる作業用端末があり、GPUノードと同じOS・バージョン(本記事ではUbuntu 24.04)であること 作業用端末に helm 、 skopeo 、 kubectl 、Docker(またはPodman)が導入されていること 作業用端末からGPUノードへSSH接続できること 作業用端末からDownstream Clusterを kubectl で操作できること(RMSから取得したkubeconfigを利用) 作業用端末とDownstream Clusterの両方から接続できる、OCI対応のコンテナレジストリ・Helmリポジトリがあること。また、Downstream Clusterの各ノードがそこからイメージを取得できること(RKE2の registries.yaml 設定など) 構築環境 本記事の検証環境は次のとおりです。GPU Operatorの各コンポーネントは、v26.3.3のデフォルトバージョンを使っています。 項目 バージョン・設定 OS Ubuntu 24.04 RKE2 v1.36.3+rke2r1 Rancher Prime v2.15.2 搭載GPU NVIDIA Tesla T4(AWS g4dn.2xlarge) コンテナレジストリ・Helmリポジトリ Harbor NVIDIA GPU Driver 580.178.04(nvidia-driver-580-server) NVIDIA GPU Operator v26.3.3 NVIDIA Container Toolkit v1.19.1 NVIDIA Device Plugin / GPU Feature Discovery v0.19.3 DCGM Exporter 4.5.3-4.8.2-distroless Node Feature Discovery v0.18.3 NVIDIA GPU Driver 設定手順 最初にGPUノードで、搭載されているGPUの種類とカーネルバージョンを確認します。カーネルバージョンは、後でカーネルヘッダをダウンロードする際に使います。 $ lspci | grep -i nvidia # 出力例 00:1e.0 3D controller: NVIDIA Corporation TU104GL [Tesla T4] (rev a1) $ uname -r # 出力例 7.0.0-1012-aws 次に、作業用端末でドライバのパッケージをダウンロードします。apt-get install –download-onlyは、実行した環境に導入済みのパッケージをダウンロード対象から外します。そこで、GPUノードと同じUbuntu 24.04のクリーンなコンテナを起動し、その中でダウンロードします。こうすると作業用端末の環境に左右されず、依存パッケージを漏れなく集められます。 $ mkdir -p ~/nvidia-driver-pkgs $ docker run --rm -it -v ~/nvidia-driver-pkgs:/pkgs ubuntu:24.04 bash コンテナ内で、利用可能なドライバを確認します。データセンター向けGPUでは、末尾が -server のパッケージを選びます。 # apt-get update # apt-cache search nvidia-driver | grep server # 出力例 nvidia-driver-470-server - NVIDIA Server Driver metapackage ・ ・ ・ nvidia-driver-580-server - NVIDIA Server Driver metapackage 使用するドライバを決めたら、カーネルヘッダとあわせてダウンロードします。ドライバのDKMSモジュールはGPUノード上でビルドされるため、GPUノードのカーネルに対応した linux-headers が必要です。指定できるバージョンは Launchpad で確認できます。 7.0.0-1012-aws のカーネルバージョンで nvidia-driver-580-server をインストールする場合は、コンテナ内で次のように実行します。ダウンロードしたパッケージは、マウントした /pkgs 経由で作業用端末の ~/nvidia-driver-pkgs に保存されます。 # apt-get install --download-only -y \ nvidia-driver-580-server=580.178.04-0ubuntu0.24.04.1 \ linux-headers-<GPUノードのカーネルバージョン> # cp /var/cache/apt/archives/*.deb /pkgs/ # exit クリーンなコンテナでダウンロードするため、GPUノードに導入済みの基本パッケージも含まれます。GPUノードのパッケージが古い場合、インストール時にそれらも更新される点に注意してください。 ダウンロードしたパッケージを、作業用端末からGPUノードに転送します。 $ scp -r -i <SSH鍵> ~/nvidia-driver-pkgs ubuntu@<GPUノードIP>:~/ GPUノード上でパッケージをインストールし、再起動します。 $ cd ~/nvidia-driver-pkgs $ apt-get install -y --no-download ./*.deb $ sudo reboot 動作確認 再起動後、インストールが正常に完了したかをGPUノード上で確認します。まず、 nvidia-smi でGPUの情報とドライババージョンが表示されることを確認します。 $ nvidia-smi # 出力例 Fri Sep 25 06:34:12 2026 +-----------------------------------------------------------------------------------------+ | NVIDIA-SMI 580.178.04 Driver Version: 580.178.04 CUDA Version: 13.0 | +-----------------------------------------+------------------------+----------------------+ | GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |=========================================+========================+======================| | 0 Tesla T4 Off | 00000000:00:1E.0 Off | 0 | | N/A 32C P0 26W / 70W | 0MiB / 15360MiB | 0% Default | | | | N/A | +-----------------------------------------+------------------------+----------------------+ +-----------------------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=========================================================================================| | No running processes found | +-----------------------------------------------------------------------------------------+ 次に、NVIDIAのカーネルモジュールがロードされていることを確認します。 $ lsmod | grep nvidia # 出力例 nvidia_uvm 2080768 0 nvidia_drm 139264 0 nvidia_modeset 1687552 1 nvidia_drm nvidia 105373696 3 nvidia_uvm,nvidia_drm,nvidia_modeset drm_ttm_helper 20480 1 nvidia_drm video 77824 1 nvidia_modeset 最後に、GPU Operatorの各コンポーネントがドライバとのやり取りに使う libnvidia-ml.so が存在することも確認しておきます( RKE2 GPU Operators )。 $ find /usr/ -iname libnvidia-ml.so* # 出力例 /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.1 /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.580.178.04 /usr/lib/x86_64-linux-gnu/libnvidia-ml.so ノードラベリング・テイント設定 GPUを使うアプリケーションだけをGPUノードに配置したい場合は、ラベルとテイントで管理します。ここからの kubectl は、Downstream Clusterのkubeconfigを設定した作業用端末(またはRancher UIのkubectlシェル)で実行します。 ラベルは、ワークロードの nodeSelector や nodeAffinity でGPUノードを指定するために付与します。GPU Operatorの導入後は nvidia.com/gpu.present=true などのラベルも自動で付与されるため、独自ラベルは運用上の必要に応じて付けてください。 $ kubectl label node <GPUノード名> accelerator=nvidia-gpu テイントは、GPUを使わないPodがGPUノードに配置されるのを防ぐために設定します。 $ kubectl taint nodes <GPUノード名> nvidia.com/gpu=dedicated:NoSchedule GPU OperatorのDaemonSetは、デフォルトで nvidia.com/gpu キーの NoSchedule テイントを許容する設定になっているため、このテイントを先に設定しても導入に影響はありません。一方、GPUを使うワークロード側には同じキーの tolerations を設定する必要があります。 NVIDIA GPU Operator 設定手順 まず、閉域内のHarborに次の2つのプロジェクトを作成します。 nvidia-chart :GPU OperatorのHelmチャート用 nvidia :GPU Operatorが使うコンテナイメージ用 プロジェクトを非公開にする場合は、Downstream Cluster側にも認証情報の設定が必要です(イメージは registries.yaml 、チャートはHelmChartリソースの認証用フィールド)。 作業用端末からNVIDIA GPU OperatorのHelmチャートをダウンロードします。 $ helm repo add nvidia https://helm.ngc.nvidia.com/nvidia $ helm repo update $ helm pull nvidia/gpu-operator --version v26.3.3 Helmリポジトリにログインし、チャートをOCI形式で登録します。本記事のHarborは自己署名証明書のためTLS検証をスキップしています。 $ helm registry login <Helmリポジトリのドメイン> \ --username <Helmリポジトリのユーザ名> \ --password <Helmリポジトリのパスワード> \ --insecure $ helm push gpu-operator-v26.3.3.tgz oci://<Helmリポジトリのドメイン>/nvidia-chart --insecure-skip-tls-verify 次に、GPU Operatorが使うコンテナイメージを skopeo でコンテナレジストリへコピーします。 コピー元イメージ 使用するコンポーネント nvcr.io/nvidia/gpu-operator:v26.3.3 GPU Operator本体、Operator Validator nvcr.io/nvidia/k8s/container-toolkit:v1.19.1 NVIDIA Container Toolkit nvcr.io/nvidia/k8s-device-plugin:v0.19.3 NVIDIA Device Plugin、GPU Feature Discovery nvcr.io/nvidia/k8s/dcgm-exporter:4.5.3-4.8.2-distroless DCGM Exporter registry.k8s.io/nfd/node-feature-discovery:v0.18.3 Node Feature Discovery ${src#*/} で先頭の nvcr.io/ を取り除き、 <コンテナレジストリのドメイン>/nvidia/... という同じ階層でコピーしています。NFDのみ取得元が異なるため、個別にコピーします。 $ REGISTRY=<コンテナレジストリのドメイン> $ skopeo login --tls-verify=false ${REGISTRY} $ for src in \ nvcr.io/nvidia/gpu-operator:v26.3.3 \ nvcr.io/nvidia/k8s/container-toolkit:v1.19.1 \ nvcr.io/nvidia/k8s-device-plugin:v0.19.3 \ nvcr.io/nvidia/k8s/dcgm-exporter:4.5.3-4.8.2-distroless; do skopeo copy --dest-tls-verify=false docker://${src} docker://${REGISTRY}/${src#*/} done $ skopeo copy --dest-tls-verify=false \ docker://registry.k8s.io/nfd/node-feature-discovery:v0.18.3 \ docker://${REGISTRY}/nvidia/node-feature-discovery:v0.18.3 RKE2のHelmChartリソースとして、GPU Operatorのインストール設定を記載した gpu-operator-helm-chart.yaml を作成します。ポイントは次の3点です。 イメージの参照先 :各コンポーネントの repository を閉域内のレジストリに向けます。 ホスト導入済みドライバの利用 : driver.enabled: false とし、使わないコンポーネントも無効にして、ミラーが必要なイメージを減らしています。MIG対応GPUを使う場合は migManager を有効にし、 k8s-mig-manager イメージもコピーしてください。 RKE2固有の設定 :RKE2のcontainerdはソケットの場所が標準と異なるため、 toolkit.env で CONTAINERD_SOCKET を指定します( RKE2 GPU Operators )。 devicePlugin.config はタイムスライシングの設定です。 replicas: 4 により、1枚の物理GPUを4つの nvidia.com/gpu として公開し、複数のPodで時分割共有できます。ただし、Pod間でGPUメモリは分離されないため、不要な場合は config ブロックごと削除してください( Time-Slicing GPUs )。 apiVersion: helm.cattle.io/v1 kind: HelmChart metadata: name: gpu-operator namespace: kube-system spec: chart: oci://<Helmリポジトリのドメイン>/nvidia-chart/gpu-operator version: v26.3.3 targetNamespace: gpu-operator createNamespace: true insecureSkipTLSVerify: true valuesContent: |- validator: repository: <コンテナレジストリのドメイン>/nvidia image: gpu-operator version: v26.3.3 operator: repository: <コンテナレジストリのドメイン>/nvidia image: gpu-operator version: v26.3.3 devicePlugin: repository: <コンテナレジストリのドメイン>/nvidia image: k8s-device-plugin version: v0.19.3 # タイムスライシングを使わない場合はconfigブロックを削除 config: create: true name: "time-slicing-config" default: "t4-sharing" data: t4-sharing: |- version: v1 flags: migStrategy: none sharing: timeSlicing: resources: - name: nvidia.com/gpu replicas: 4 dcgmExporter: repository: <コンテナレジストリのドメイン>/nvidia/k8s image: dcgm-exporter version: 4.5.3-4.8.2-distroless gfd: repository: <コンテナレジストリのドメイン>/nvidia image: k8s-device-plugin version: v0.19.3 toolkit: repository: <コンテナレジストリのドメイン>/nvidia/k8s image: container-toolkit version: v1.19.1 env: - name: CONTAINERD_SOCKET value: /run/k3s/containerd/containerd.sock node-feature-discovery: image: repository: <コンテナレジストリのドメイン>/nvidia/node-feature-discovery tag: v0.18.3 # ホストにドライバを導入済みのため無効化 driver: enabled: false # 本記事では使わないコンポーネント migManager: enabled: false vgpuDeviceManager: enabled: false vfioManager: enabled: false sandboxDevicePlugin: enabled: false kataSandboxDevicePlugin: enabled: false ccManager: enabled: false 作成したHelmChartリソースをDownstream Clusterに適用します。RKE2のHelm Controllerがチャートを取得し、GPU Operatorをインストールします。 $ kubectl apply -f gpu-operator-helm-chart.yaml Container Toolkitは設定を反映するためにcontainerdへ再読み込みを指示し、その影響でGPUノードのRKE2が再起動します。稼働中のワークロードがある場合は、作業タイミングに注意してください。 動作確認 GPU OperatorのPodがすべて Running または Completed になっていることを確認します。出力例はGPUノード2台の環境のものです。 $ kubectl get pod -n gpu-operator # 出力例 NAME READY STATUS RESTARTS AGE gpu-feature-discovery-8t85l 2/2 Running 0 5m gpu-feature-discovery-kkwbb 2/2 Running 0 5m gpu-operator-7974d8cf9-qq7bh 1/1 Running 0 5m gpu-operator-node-feature-discovery-gc-5c84b6f5c4-tmf9k 1/1 Running 0 5m gpu-operator-node-feature-discovery-master-6db6986c58-bjdsg 1/1 Running 0 5m gpu-operator-node-feature-discovery-worker-55v8j 1/1 Running 0 5m gpu-operator-node-feature-discovery-worker-b944b 1/1 Running 0 5m gpu-operator-node-feature-discovery-worker-cxrxs 1/1 Running 0 5m gpu-operator-node-feature-discovery-worker-kmmv2 1/1 Running 0 5m gpu-operator-node-feature-discovery-worker-qnz9w 1/1 Running 0 5m gpu-operator-node-feature-discovery-worker-wxln9 1/1 Running 0 5m nvidia-container-toolkit-daemonset-4kkbt 1/1 Running 0 5m nvidia-container-toolkit-daemonset-vbgnc 1/1 Running 0 5m nvidia-cuda-validator-b8grf 0/1 Completed 0 5m nvidia-cuda-validator-z7skc 0/1 Completed 0 5m nvidia-dcgm-exporter-6dhd5 1/1 Running 0 5m nvidia-dcgm-exporter-8mhhp 1/1 Running 0 5m nvidia-device-plugin-daemonset-6v4xz 2/2 Running 0 5m nvidia-device-plugin-daemonset-snx4x 2/2 Running 0 5m nvidia-operator-validator-4ldlj 1/1 Running 0 5m nvidia-operator-validator-kctw6 1/1 Running 0 5m GPU Operator全体の状態を表すClusterPolicyが ready になっていることも確認します。 $ kubectl get clusterpolicy # 出力例 NAME STATUS AGE cluster-policy ready <作成日時> 以下のコマンドを実行し、GPUノードのラベルに nvidia.com/gpu.machine などのGPU関連ラベルが付与されていることを確認します。 $ kubectl get node <GPUノード名> -o jsonpath='{.metadata.labels}' | tr ',' '\n' | grep "nvidia.com" # 出力例 "nvidia.com/cuda.driver-version.full":"580.178.04" "nvidia.com/cuda.driver-version.major":"580" "nvidia.com/cuda.driver-version.minor":"178" "nvidia.com/cuda.driver-version.revision":"04" "nvidia.com/cuda.driver.major":"580" "nvidia.com/cuda.driver.minor":"178" "nvidia.com/cuda.driver.rev":"04" "nvidia.com/cuda.runtime-version.full":"13.0" "nvidia.com/cuda.runtime-version.major":"13" "nvidia.com/cuda.runtime-version.minor":"0" "nvidia.com/cuda.runtime.major":"13" "nvidia.com/cuda.runtime.minor":"0" "nvidia.com/gfd.timestamp":"1790646472" "nvidia.com/gpu.compute.major":"7" "nvidia.com/gpu.compute.minor":"5" "nvidia.com/gpu.count":"1" "nvidia.com/gpu.deploy.container-toolkit":"true" "nvidia.com/gpu.deploy.dcgm":"true" "nvidia.com/gpu.deploy.dcgm-exporter":"true" "nvidia.com/gpu.deploy.device-plugin":"true" "nvidia.com/gpu.deploy.driver":"true" "nvidia.com/gpu.deploy.gpu-feature-discovery":"true" "nvidia.com/gpu.deploy.node-status-exporter":"true" "nvidia.com/gpu.deploy.operator-validator":"true" "nvidia.com/gpu.family":"turing" "nvidia.com/gpu.machine":"g4dn.2xlarge" "nvidia.com/gpu.memory":"15360" "nvidia.com/gpu.mode":"compute" "nvidia.com/gpu.present":"true" "nvidia.com/gpu.product":"Tesla-T4-SHARED" "nvidia.com/gpu.replicas":"4" "nvidia.com/gpu.sharing-strategy":"time-slicing" "nvidia.com/mig.capable":"false" "nvidia.com/mig.strategy":"single" "nvidia.com/mps.capable":"false" "nvidia.com/vgpu.present":"false" ノードの割り当て可能リソースに nvidia.com/gpu が追加されていることを確認します。値は「物理GPUの枚数 × タイムスライシングのreplicas」で、本記事では1 × 4 = 4です。タイムスライシングを使わない場合は物理GPUの枚数と一致します。 $ kubectl get node <GPUノード名> -o jsonpath='{.status.allocatable}' # 出力例 {"cpu":"8","ephemeral-storage":"196555267123","hugepages-1Gi":"0","hugepages-2Mi":"0","memory":"32479456Ki","nvidia.com/gpu":"4","pods":"110"} GPUノード上で、NVIDIAコンテナランタイムのバイナリが配置され、RKE2のcontainerd設定にNVIDIAランタイムが追加されていることを確認します。 $ ls /usr/local/nvidia/toolkit/nvidia-container-runtime # 出力例 /usr/local/nvidia/toolkit/nvidia-container-runtime $ grep nvidia /var/lib/rancher/rke2/agent/etc/containerd/config.toml # 出力例 [plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.'nvidia'] [plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.'nvidia'.options] BinaryName = "/usr/local/nvidia/toolkit/nvidia-container-runtime" [plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.'nvidia-cdi'] [plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.'nvidia-cdi'.options] BinaryName = "/usr/local/nvidia/toolkit/nvidia-container-runtime.cdi" おわりに 本記事では、AirGap環境のRKE2クラスタに対して、ホストへのNVIDIA GPU Driverの導入と、HelmChartリソースによるNVIDIA GPU Operatorの導入を行いました。AirGap環境では、依存パッケージを漏れなく集めることと、イメージの参照先をすべて閉域内のレジストリに向けることが主なポイントです。 これで、GPUを使うAIアプリケーションをクラスタ上で動かす準備が整いました。次回はSUSE AI Factoryのインストール方法について解説したいと思います。 参考 About the NVIDIA GPU Operator Installing the NVIDIA GPU Operator Install NVIDIA GPU Operator in Air-Gapped Environments NVIDIA GPU Operator Release Notes NVIDIA GPU Operator Platform Support Time-Slicing GPUs in Kubernetes RKE2 Documentation – GPU Operators nvidia-graphics-drivers-580-server package in Ubuntu(Launchpad) ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post SUSE RancherでのGPUノード設定方法解説 〜AirGap環境へのNVIDIA GPU Driver・GPU Operator導入〜 first appeared on SIOS Tech Lab .
はじめに セーフィー株式会社の鈴木です。 社内のGitHub組織でGitHub ActionsやAWS上の踏み台サーバーからGitHubリポジトリを操作する際の認証に、OIDCトークンを短命なGitHubアクセストークンへ交換するSecurity Token Serviceである sorah/sts-cat を導入しました。これによりGitHub Appの秘密鍵やPersonal Access Tokenといった長寿命の秘密情報を実行環境に置かずにGitHubの権限を利用できるようになりました。 本記事では、導入の背景・構成・設計上の判断・導入時に気づいた点をまとめます。 背景

動画

該当するコンテンツが見つかりませんでした

書籍