Amazon Web Services ブログ

CDK8s+ が一般利用開始並びにマニフェスト検証機能をサポート

はじめに

2020 年 7 月に CDK8s+ のベータ版を紹介しました。CDK8s+ は、Kubernetes リソースのマニフェストをより効率的に書けるように設計された、高レベルのIntent driven (後述) な API です。リリース以降、機能の追加やお客様からのフィードバックの収集に取り組んできました。

本日、CDK8s+ が一般利用可能になり、最初のメジャーバージョンの提供を開始したことをお知らせいたします。 つまり、少なくとも次のメジャーバージョンまで破壊的な変更が行われず、安定して使用できるということです。これは、昨年末のリリースとともに、CDK8s ツールチェーン全体 (Cloud Native Computing Foundation [CNCF] プロジェクト) が一般利用可能になって、安定して使用できることを示しています。

  • CDK8s の使用を開始するには、こちらの Web サイトにアクセスして詳細を確認し、入門ガイドを参照してください。

ソリューションの概要

最近では、クラウド内のアプリケーションに関連する全領域のOwnership を、アプリケーション開発者が持てるようにする企業がますます増えています。 これには、Kubernetes マニフェストの作成も含まれています。 アプリケーション開発者が Kubernetes マニフェスト作成の Ownership を持つことで、ボトルネックを取り除き、より大規模かつ速く開発プロセスを回すことにつながるでしょう。 ただし、プロダクショングレードの Kubernetes マニフェスト作成は、時に複雑で難しく、アプリケーション開発者が通常持っていない経験を必要とします。 他のテクノロジーと同様、ターゲットとなるユーザーが増えるとともに、この複雑さを軽減していく必要があります。 ソフトウェアは、さまざまな形式で抽象化することでこの複雑さを軽減しています。 CDK8s+ は、Kubernetes マニフェストの複雑さを軽減し、保守性を向上させることに重きを置いて設計された API 抽象化です。 これはシンプルな API でコアな Kubernetes リソースを使えるようにする Constructs を提供します。

チュートリアル

理解を深めるために、最近 CDK8s+ に追加されたいくつかの主要な機能を見て、それらを使用して複雑な Kubernetes アプリケーションを構成するために必要なことを見ていきましょう。

Pod のネットワークを分離して、特定の通信のみを許可する

デフォルトでは、Kubernetes Pod はすべての入出力の通信がオープンになっています。 これは開発中は便利かもしれませんが、プロダクション環境のデプロイでは、ネットワーク通信を制限して必要最低限しか許可しない、よりセキュアな設定が必要です。Kubernetes では、複数の Network Policies を設定することでこれを実現します。CDK8s+では、以下のように書きます。

const web = new kplus.Deployment(this, 'Web', {
  containers: [{ image: 'web:latest' }],
  isolate: true,
});

const cache = new kplus.Deployment(this, 'Cache', {
  containers: [{ image: 'cache:latest' }],
  isolate: true,
});

web.connections.allowTo(cache);

2 つの独立した Pod (つまりネットワークアクセスが全くない Pod) を作成し、この 2 つの Pod 間通信を明示的に許可します。これにより、Web Pod は Cache Pod 以外の Pod にアクセスできませんし、Web 以外の Pod は Cache Pod に接続できません。

  • 一方、同じことを実現するために必要となる純粋な YAML マニフェストはこちらです。

追加の Pod が Cache Pod にアクセスする必要がある場合は、その接続を許可するだけで済みます。

例:

// a batch job running computations that should 
// populate the cache once an hour.
const batch = new kplus.CronJob(this, 'Batch', {
  containers: [{ image: 'web:latest' }],
  schedule: Cron.hourly(),
});

cache.connections.allowFrom(batch);

ここまで読むと、冒頭で CDK8s+を Intent driven と定義した理由がわかってくると思います。作者の意図 (Intent) を汲み取り、基礎となるメカニズムを使用してその意図を実装するよう、API が設計されています。ここでいう意図とは、ネットワーク通信の制限であり、その仕組みとは Network Policies のことです。

  • Network Policies を使用するには、Network Policy Provider をクラスターにインストールする必要があります。詳細については、前提条件を参照してください。

複数の Pod を同じノードで実行するようにスケジューリングする

時には、アプリケーション内の異なるサービスを同じホストにデプロイしたいことがあります。たとえば、キャッシュサービスからのレイテンシーを減らすためには、読み取り側のサービスをキャッシュサービスのできるだけ近くにデプロイしたいと考えるでしょう。

Kubernetesでは、関連する Pod に affinity rules を設定することでこれを実現できます。CDK8s+では、以下のように書きます。

const web = new kplus.Deployment(this, 'Web', {
  containers: [{ image: 'web:latest' }],
  isolate: true,
});

const cache = new kplus.Deployment(this, 'Cache', {
  containers: [{ image: 'cache:latest' }],
  isolate: true,
});

web.scheduling.colocate(cache);

繰り返しになりますが、CDK8s+ を使うと Intent ベースな実装になっていることがわかると思います。 この場合、意図は 異なる Pod を同じノードに配置することであり、仕組みは affinity rules です。

  • 一方、同じことを実現するために必要となる純粋な YAML マニフェストはこちらです。

CDK8s+ には、単純化された API に加えて、マニフェストの安全性を高め、設定ミスから保護するための Kubernetes のデフォルト設定がいくつか用意されています。たとえば、CDK8s+ はデフォルトでコンテナの readOnlyRootFileSystem プロパティを true に設定します。これは、特にプロダクションワークロードではベストプラクティスと考えられています。しかし、ヒューマンエラーは起こり得るものであり、コーディング時に完全に回避する方法はありません。そこで、ポリシーを強制するエンフォースメントツールの出番です。

設定ミスへの対策

Kubernetesは、アプリケーション開発者が自分のコードを実行するインフラをコントロールする手段を提供する、素晴らしいテクノロジーです。 CDK8s はこれをさらに一歩推し進めたものです。開発者にとって最も身近な方法、つまりコードでインフラをコントロールする手段を提供します。

しかし、開発者に大きな責任を負わせると、設定ミスをするリスクも大きくなります。 プロの Site Reliability Engineers (SRE) とは異なり、開発者は Kubernetes の細かなところまでは精通していないため、間違いを犯しがちです。 こうしたミスのよくある例としては、Liveness Probe や Readiness Probe なしでワークロードをデプロイしたり、コンテナにルートアクセス権限を付与してしまうことです。これは、Kubernetes クラスターの安定性とセキュリティを脅かします。 この種の設定ミスは、Kubernetes ではきわめて一般的なものであり、特にテクノロジーがオープンエンドであることが理由です。Kubernetes は好きなように設定できますが、それは同時に設定ミスも起こりうるということです。 Red Hat が発表した 「2022 State of Kubernetes Security Report」 によると、Kubernetes 管理者の 53% が設定ミスによるインシデントを経験しているのは当然と言えるでしょう。

このため、我々は Datree と提携し、サードパーティのポリシーエンフォースメントツールで CDK8s+ が生成するマニフェストを検証できるように、拡張可能なプラグイン機構を設計・実装しました。外部のサードパーティツールだけでなく、組織内の内部ツールに対しても、独自のプラグインを実装可能です。

  • これらのプラグインの実装方法については、こちらを参照してください。

本日、そのような実装の 1 つである Datree plugin for cdk8s を発表できることを嬉しく思います。 Datree は、マニフェストにポリシーを適用することで、Kubernetesの設定ミスを防止します。 クラスターまたは継続的インテグレーションプロセスに直接統合でき、すべての設定変更をスキャンし、ポリシーに準拠していないものをブロックします。CDK8s の設定に Datree を追加すると、cdk8s synth を実行するたびに、生成されたマニフェストが Datree の専用ポリシーで自動的に検証され、見逃していたかもしれない設定ミスが特定できます。

実際に見ていきましょう!

まず、統合を開始するために、cdk8s.yaml の設定を以下のように編集する必要があります。

language: typescript
app: node main.js
imports:
  - k8s
validations:
  - package: '@datreeio/datree-cdk8s'
    class: DatreeValidation
    version: 1.3.4

この記事を通して紹介した CDK8s+ のコード(完全なアプリケーション形式)を使用します。

import { Construct } from 'constructs';
import { App, Chart, ChartProps } from 'cdk8s';
import * as kplus from 'cdk8s-plus-24';

export class MyChart extends Chart {
  constructor(scope: Construct, id: string, props: ChartProps = { }) {
    super(scope, id, props);

    const web = new kplus.Deployment(this, 'Web', {
      containers: [{ image: 'web:latest' }],
      isolate: true,
    });

    const cache = new kplus.Deployment(this, 'Cache', {
      containers: [{ image: 'cache:latest' }],
      isolate: true,
    });

    web.connections.allowTo(cache);
    web.scheduling.colocate(cache);

  }
}

const app = new App();
new MyChart(app, 'cdk8s-app');
app.synth();

次のステップでは、cdk8s synth を実行して何が起こるかを確認します。

❯ cdk8s synth                                                                                                                                                                                                                                                             [23:00:55]
Synthesizing application
  - dist/cdk8s-app.k8s.yaml
Performing validations
🌳 Datree validating dist/cdk8s-app.k8s.yaml with policy cdk8s
Validations finished

Validation Report (@datreeio/datree-cdk8s@1.3.4)------------------------------------------------

(Summary)

╔═══════════╤════════════════════════╗
║ Status    │ failure                ║
╟───────────┼────────────────────────╢
║ Plugin    │ @datreeio/datree-cdk8s ║
╟───────────┼────────────────────────╢
║ Version   │ 1.3.4                  ║
╟───────────┼────────────────────────╢
║ Customize │ https://app.datree.io  ║
║ policy    │                        ║
╚═══════════╧════════════════════════╝


(Violations)

Ensure each container image has a pinned (tag) version (2 occurrences)

  Occurrences:

    - Construct Path: cdk8s-app/Web/Resource
    - Manifest Path: ./dist/cdk8s-app.k8s.yaml
    - Resource Name: cdk8s-app-web-c825557e
    - Locations:
      > spec/template/spec/containers/0/image (line: 31:18)

    - Construct Path: cdk8s-app/Cache/Resource
    - Manifest Path: ./dist/cdk8s-app.k8s.yaml
    - Resource Name: cdk8s-app-cache-c8fee821
    - Locations:
      > spec/template/spec/containers/0/image (line: 112:18)

  Recommendation: Incorrect value for key `image` - specify an image version to avoid unpleasant "version surprises" in the future
  How to fix: https://hub.datree.io/ensure-image-pinned-version

Validation failed. See above reports for details

Datree プラグインがマニフェストを検証し、設定ミスを検出したことがわかります。 web および cache のコンテナイメージのバージョンを指定せず、latest タグを使用していたことが原因です。これらのコンテナイメージを取得するたびにそのバージョンが異なりうるため、一貫性のないデプロイメントとなり、バッドプラクティスだと考えられています。コードを破壊したり、その他の望ましくない未検証の影響を及ぼす可能性があります。このレポートでは、違反が発生した Construct や、生成された YAML マニフェスト内の違反の正確な位置を示しています。また、違反自体に関するより詳細な情報とともに、それを修正する方法に関する推奨事項も記載されています。

結論

CDK8s+ がいかに Kubernetes マニフェストを効率的に実装できるようにし、より多くの人に親しみやすいものにしているかを、いくつかのサンプルを例に見てきました。この他にも多くのサンプルがあり、今後さらに増えていく予定です。 現在、すべてのサンプルは安定しており、プロダクション環境で利用いただけます。

次に、CDK8s+ がどのように Datree などのサードパーティのポリシーエンフォースメントツールと統合して、マニフェスト内の設定ミスを防止し、クラスターに到達しないようにするガードレールを提供する方法をご覧いただきました。

最後に、このコンテンツは完全にオープンソースであり、GitHub リポジトリでフィードバックをお待ちしております。 また、Slack チャネルや Twitter (#cdk8s #cdk8s+) でのディスカッションにもぜひご参加ください。

Happy authoring!

翻訳はソリューションアーキテクトの濵が担当しました。原文はこちらです。