ホームページ  >  記事  >  バックエンド開発  >  Kubernetes ジョブを使用して OpenSSF スコアカードをスケールする方法

Kubernetes ジョブを使用して OpenSSF スコアカードをスケールする方法

WBOY
WBOYオリジナル
2024-08-09 10:20:52998ブラウズ

How we use Kubernetes jobs to scale OpenSSF Scorecard

私たちは最近、OpenSauced プラットフォーム上の OpenSSF Scorecard との統合をリリースしました。 OpenSSF スコアカードは、誰でもプロジェクトと依存関係のセキュリティ体制を理解するために使用できる強力な Go コマンド ライン インターフェイスです。危険なワークフロー、CICD のベスト プラクティス、プロジェクトがまだ維持されているかどうかなど、いくつかのチェックが実行されます。これにより、ソフトウェア ビルダーと消費者はセキュリティの全体像を理解し、プロジェクトが安全に使用できるかどうか、セキュリティ慣行のどこを改善する必要があるかを推測できるようになります。

しかし、OpenSSF Scorecard を OpenSauced プラットフォームに統合するという私たちの目標の 1 つは、これをより広範なオープンソース エコシステム全体で利用できるようにすることでした。 GitHub 上のリポジトリの場合、そのスコアを表示できるようにしたいと考えました。これは、Scorecard CLI を拡張して、GitHub 上のほぼすべてのリポジトリをターゲットにすることを意味しました。言うは易し行うは難し!

このブログ投稿では、Kubernetes を使用してこれをどのように実行したか、そしてこの統合の実装に関してどのような技術的な決定を行ったかについて詳しく説明します。

無数のリポジトリにわたってスコアを頻繁に更新する cron タイプのマイクロサービスを構築する必要があることはわかっていました。本当の問題は、それをどのように行うかということでした。スコアカード CLI をアドホックに実行するのは意味がありません。プラットフォームは簡単に圧倒されてしまう可能性があるため、OpenSauced リポジトリ ページがまだ公開されていない場合でも、オープン ソース エコシステム全体のスコアについてより詳細な分析を実行できるようにしたいと考えていました。最近訪れた。当初、私たちは Scorecard Go ライブラリを直接依存するコードとして使用し、単一のモノリシック マイクロサービス内でスコアカード チェックを実行することを検討していました。また、サーバーレス ジョブを使用して、個々のリポジトリの結果を返す 1 回限りのスコアカード コンテナを実行することも検討しました。

私たちが最終的にたどり着いた、シンプルさ、柔軟性、パワーを兼ね備えたアプローチは、Kubernetes ジョブを大規模に使用し、すべて「スケジューラー」Kubernetes コントローラー マイクロサービスによって管理されるというものです。スコアカードとのより深いコード統合を構築する代わりに、Kubernetes ジョブを 1 つだけ実行すると、サーバーレス アプローチを使用する場合と同じ利点が得られますが、すべてを Kubernetes クラスター上で直接管理するため、コストが削減されます。また、ジョブは実行方法に大きな柔軟性をもたらします。タイムアウトを長く延長したり、ディスクを使用したり、他の Kubernetes パラダイムと同様に、複数のポッドで異なるタスクを実行したりできます。

このシステムの個々のコンポーネントを分解して、それらがどのように機能するかを詳しく見てみましょう:

このシステムの最初で最も大きな部分は「scorecard-k8s-scheduler」です。クラスター上で新しいジョブを開始する Kubernetes コントローラーのようなマイクロサービス。このマイクロサービスは、従来の Kubernetes コントローラーまたはオペレーターを構築するときに使用される原則、パターン、およびメソッドの多くに従いますが、クラスター上のカスタム リソースを監視したり、変更したりすることはありません。その機能は、Scorecard CLI を実行する Kubernetes ジョブを単純に開始し、完了したジョブの結果を収集することです。

まず、Go コードのメイン制御ループを見てみましょう。このマイクロサービスは、Kubernetes Client-Go ライブラリを使用して、マイクロサービスが実行されているクラスターと直接インターフェイスします。これは、クラスター上の構成およびクライアントと呼ばれることがよくあります。コード内では、クラスター上のクライアントをブートストラップした後、データベース内の更新が必要なリポジトリをポーリングします。いくつかのリポジトリが見つかったら、個々のワーカー「スレッド」で Kubernetes ジョブを開始し、各ジョブが終了するのを待ちます。

// buffered channel, sort of like semaphores, for threaded working
sem := make(chan bool, numConcurrentJobs)

// continuous control loop
for {
    // blocks on getting semaphore off buffered channel
    sem <- true

    go func() {
        // release the hold on the channel for this Go routine when done
        defer func() {
            <-sem
        }()

        // grab repo needing update, start scorecard Kubernetes Job on-cluster,
        // wait for results, etc. etc.

        // sleep the configured amount of time to relieve backpressure
        time.Sleep(backoff)
    }()
}

バッファリングされたチャネルを使用したこの「無限制御ループ」メソッドは、構成された数のスレッドのみを使用して継続的に何かを実行する Go の一般的な方法です。同時に実行される Go 関数の数は、「numConcurrentJobs」変数の設定値によって異なります。これにより、バッファリングされたチャネルが、同時に実行される Go 関数の数を示すワーカー プールまたはセマフォとして機能するように設定されます。バッファーされたチャネルはすべてのスレッドが使用および検査できる共有リソースであるため、私はこれをセマフォ、つまり複数のスレッドがロックしてアクセスできるミューテックスとよく似たリソースとして考えることを好みます。私たちの実稼働環境では、このスケジューラーのすべてを同時に実行するスレッドの数を調整しました。実際のスケジューラは計算量がそれほど多くなく、ジョブを開始して最終的に結果が表示されるのを待つだけなので、このスケジューラが管理できる範囲を広げることができます。また、必要に応じてプレッシャーを軽減しようとするバックオフ システムも組み込まれています。このシステムは、エラーがある場合、またはスコアを計算するためのリポジトリが見つからない場合に、設定された「バックオフ」値を増分します。これにより、データベースに継続的にクエリを実行することがなくなり、スコアカード スケジューラ自体が「待機」状態を維持できるため、クラスター上の貴重なコンピューティング リソースが占有されなくなります。

制御ループ内で、いくつかのことを行います。まず、スコアカードの更新が必要なリポジトリについてデータベースにクエリを実行します。これは、監視し、インデックスを作成するタイムスタンプ メタデータに基づく単純なデータベース クエリです。リポジトリの最後のスコアが計算されてから、設定された時間が経過すると、スコアカード CLI を実行する Kubernetes ジョブによって処理されるようにバブルアップされます。

次に、スコアを取得するリポジトリを取得したら、「gcr.io/openssf/scorecard」イメージを使用して Kubernetes ジョブを開始します。 Client-Go を使用して Go コードでこのジョブをブートストラップする方法は、yaml で行う方法と非常によく似ていますが、「k8s.io」インポート経由で利用可能なさまざまなライブラリと API を使用し、プログラムで実行するだけです。

// defines the Kubernetes Job and its spec
job := &batchv1.Job{
    // structs and details for the actual Job
    // including metav1.ObjectMeta and batchv1.JobSpec
}

// create the actual Job on cluster
// using the in-cluster config and client
return s.clientset.BatchV1().Jobs(ScorecardNamespace).Create(ctx, job, metav1.CreateOptions{})

ジョブが作成された後、ジョブが完了またはエラーを通知するまで待ちます。 kubectl と同様に、Client-Go はリソースを「監視」し、変更時の状態を観察する便利な方法を提供します。

// watch selector for the job name on cluster
watch, err := s.clientset.BatchV1().Jobs(ScorecardNamespace).Watch(ctx, metav1.ListOptions{
    FieldSelector: "metadata.name=" + jobName,
})

// continuously pop off the watch results channel for job status
for event := range watch.ResultChan() {
        // wait for job success, error, or other states
}

最後に、ジョブが正常に完了したら、スコアカード CLI からの実際の JSON 結果を含むジョブのポッド ログから結果を取得できます。これらの結果が得られたら、スコアを更新/挿入してデータベースに戻し、必要なメタデータを変更して、他のマイクロサービスまたは OpenSauced API に新しいスコアがあることを知らせることができます。

前に述べたように、scorecard-k8s-scheduler では、任意の数の同時ジョブを同時に実行できます。実稼働設定では、多数のジョブを一度に実行しており、すべてこのマイクロサービスによって管理されています。その目的は、GitHub 上のすべてのリポジトリにわたってスコアを 2 週間ごとに更新できるようにすることです。このような規模により、オープンソースのメンテナーや消費者に強力なツールと洞察を提供できることを期待しています!

「スケジューラー」マイクロサービスは、最終的にはこのシステム全体の小さな部分になります。Kubernetes コントローラーに詳しい人なら誰でも、システムを機能させるために必要な追加の Kubernetes インフラストラクチャがあることを知っています。私たちの場合、マイクロサービスがクラスター上にジョブを作成できるようにするには、ロールベースのアクセス制御 (RBAC) が必要でした。

まず、サービス アカウントが必要です。これはスケジューラによって使用され、アクセス制御がバインドされているアカウントです。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: scorecard-sa
  namespace: scorecard-ns

このサービス アカウントは、すべてが実行される「scorecard-ns」名前空間に配置されます。

次に、サービス アカウントのロールとロール バインディングを設定する必要があります。これには、実際のアクセス制御 (ジョブの作成、ポッド ログの表示など) が含まれます

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: scorecard-scheduler-role
  namespace: scorecard-ns
rules:
- apiGroups: ["batch"]
  resources: ["jobs"]
  verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
- apiGroups: [""]
  resources: ["pods", "pods/log"]
  verbs: ["get", "list", "watch"]

—

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: scorecard-scheduler-role-binding
  namespace: scorecard-ns
subjects:
- kind: ServiceAccount
  name: scorecard-sa
  namespace: scorecard-ns
roleRef:
  kind: Role
  name: scorecard-scheduler-role
  apiGroup: rbac.authorization.k8s.io

「ポッドとポッド ログを取得するために、なぜこのサービス アカウントにアクセス権を与える必要があるの?」と疑問に思われるかもしれません。それはアクセス制御の行き過ぎではないでしょうか?」覚えて!ジョブにはポッドがあり、スコアカード CLI の実際の結果が含まれるポッド ログを取得するには、ジョブからポッドをリストし、そのログを読み取ることができる必要があります。

この 2 番目の部分である「RoleBinding」では、実際にサービス アカウントにロールをアタッチします。このサービス アカウントは、クラスター上で新しいジョブを開始するときに使用できます。

Alex Ellis と彼の優れた実行ジョブ コントローラーに大いに感謝します。これは、Client-Go をジョブで正しく使用するための大きなインスピレーションと参考になりました!

皆さん生意気でいてください!

以上がKubernetes ジョブを使用して OpenSSF スコアカードをスケールする方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。