本番環境での Google Kubernetes Engine の準備

このソリューションは、安全性、信頼性、および費用対効果の高い方法でワークロードを Google Kubernetes Engine に展開するためのブループリントと方法を提供します。クラスタへの管理アクセスおよびネットワーク アクセスを構成するためのガイダンスを提供します。この記事では、Kubernetes リソースとクラスタ管理について実践的に理解し、Google Cloud Platform(GCP)ネットワーク機能に精通していることを前提としています。

プロジェクト、Virtual Private Cloud(VPC)ネットワーク、クラスタの構造化

次の図は、プロジェクト、VPC ネットワーク、リージョン、サブネットワーク、ゾーン、およびクラスタに最適な構造を示しています。

プロジェクト、ネットワーク、クラスタ構造

プロジェクト

GCP はプロジェクト エンティティ内にそのすべてのリソースを作成します。プロジェクトは課金単位であり、管理者は Cloud Identity and Access Management(Cloud IAM)の役割をユーザーに関連付けることができます。プロジェクト レベルで役割が適用されると、プロジェクト内にカプセル化されたすべてのリソースに、その役割が適用されます。

さまざまなオペレーティング環境のカプセル化にはプロジェクトを使用する必要があります。たとえば、オペレーション チーム向けには production および staging のプロジェクトを設定し、デベロッパー向けには test-dev プロジェクトを設定するなどです。最もミッション クリティカルで機密性の高いデータとワークロードを保持するプロジェクトには、より詳細で厳格なポリシーを適用する一方、test-dev 環境のデベロッパーには、実験のための制限が緩やかで柔軟なポリシーを適用できます。

クラスタ

プロジェクトには複数のクラスタを含めることができます。複数のワークロードをデプロイする場合、それらのワークロードに単一の共有クラスタ、または個別のクラスタのいずれを使用するかを選択できます。決定する際の参考として、GKE クラスタのサイズとスコープの選択に関しておすすめする方法を検討してください。

ネットワークとサブネットワーク

各プロジェクト内では、1 つ以上の VPC ネットワークを使用できます。VPC ネットワークは、物理ネットワークの仮想バージョンです。各 VPC ネットワークは、ネットワーク関連の他のリソース(サブネットワーク、外部 IP アドレス、ファイアウォール ルール、ルート、VPN、Cloud Router など)が含まれるグローバル リソースです。VPC ネットワーク内では、リージョン リソースであるサブネットワークを使用して、GKE クラスタ間の各リージョン内外へのトラフィックを分離して制御できます。

各プロジェクトには、1 つのデフォルト ネットワークが付属しています。追加のネットワークを作成して、既存の IP アドレス管理(IPAM)規則にマップするように構成できます。そのネットワークにファイアウォール ルールを適用することで、GKE ノードに出入りするトラフィックをフィルタできます。デフォルトでは、GKE ノードへのすべてのインターネット トラフィックが拒否されます。

サブネットワーク間の通信を制御するには、それらのサブネットワーク間でのトラフィックの受け渡しを許可するファイアウォール ルールを作成する必要があります。ファイアウォール ルールを有効にするには、クラスタまたはノードプールの作成時に --tags フラグを使用して、GKE ノードに適切なタグを付けます。必要に応じて、タグを使用してサブネットワーク間のルートを作成することもできます。

マルチゾーン クラスタとリージョン クラスタ

デフォルトでは、クラスタは作成時に指定された単一のゾーン内にクラスタ マスターとノードを作成します。マルチゾーン クラスタまたはリージョン クラスタを作成することにより、クラスタの可用性と復元力を向上させることができます。マルチゾーン クラスタとリージョン クラスタは、リージョン内の複数のゾーンに Kubernetes リソースを分散させます。

マルチゾーン クラスタ:

  • 1 つのゾーンに単一のクラスタ マスターを作成します。
  • 複数のゾーンにノードを作成します。

リージョン クラスタ:

  • 3 つのゾーンに 3 つのクラスタ マスターを作成します。
  • デフォルトでは 3 つのゾーンにノードを作成しますが、必要に応じて、必要な数のゾーンにノードを作成できます。

リージョン クラスタとマルチゾーン クラスタの主な違いは、リージョン クラスタは 3 つのクラスタ マスターを作成する一方、マルチゾーン クラスタが作成するクラスタ マスターは 1 つだけであるという点です。いずれの場合も、複数のゾーンにまたがるノード間トラフィックに対しては料金が発生します。

クラスタの作成時に、マルチゾーン クラスタまたはリージョン クラスタを作成することを選択できます。マルチゾーン クラスタを作成するには、既存のクラスタに新しいノードを追加します。一方、既存のクラスタをリージョン クラスタに変更することはできません。リージョン クラスタを非リージョン クラスタに変更することもできません。

マルチゾーン クラスタとリージョン クラスタについて詳しくは、GKE のドキュメントをご覧ください。

ID とアクセスの管理

プロジェクト レベルのアクセス

前のセクションで、プロジェクト レベルで IAM の役割をユーザーにバインドできることを説明しました。個々のユーザーに役割を付与するだけでなく、グループを使用して、役割の適用を簡単にすることもできます。

以下の図に、開発者が今後の機能とバグ修正を開発してテストするために設定された開発プロジェクトと、本番環境トラフィック用の prod プロジェクトに、最小権限の原則を提供する IAM ポリシー レイアウトを示します。

ID とアクセスの管理

次の表に示すように、組織内には、2 つのプロジェクト全体で IAM の役割を通じて許可された、さまざまなレベルの権限を持つ 4 つのユーザーのグループがあります。

チーム IAM の役割 プロジェクト 権限
開発 container.developer dev プロジェクト内に、既存のクラスタ用の Kubernetes リソースを作成することはできますが、クラスタを作成または削除することはできません。
運用 container.admin prod プロジェクト内で実行されているクラスタおよび Kubernetes リソースへの完全な管理アクセス。
セキュリティ container.viewer
security.admin
prod ファイアウォール ルールと SSL 証明書の作成、変更、削除、ならびに実行中のポッドのログを含む各クラスタ内で作成されたリソースの表示。
ネットワーク network.admin prod ネットワーキング リソース(ファイアウォール ルールと SSL 証明書を除く)の作成、変更、削除。

prod プロジェクトに対するアクセス権を持つ 3 チームに加えて、追加のサービス アカウントprod に対する container.developer の役割が付与され、クラスタ内でリソースを作成、一覧表示、削除できるようになります。サービス アカウントを使用すると、自動化スクリプトやデプロイ フレームワークに、自動的に処理する機能を与えることができます。本番環境プロジェクトとクラスタへのデプロイは、自動化されたパイプラインで進められるはずです。

dev プロジェクトには、同じクラスタ内の同じアプリケーションを操作する複数の開発者がいます。これは、クラスタ ユーザーが作成できる名前空間によって容易になります。各開発者は、独自の名前空間内にリソースを作成できるため、名前の競合が避けられます。また、同じ YAML 構成ファイルをデプロイに再利用できるので、開発の繰り返し時に可能な限り同じ構成が維持されます。名前空間を使用して、クラスタ内の CPU、メモリ、ストレージの使用の割り当てを作成して、1 人の開発者が使用するクラスタ内のリソースが多すぎないようにすることもできます。次のセクションでは、特定の名前空間内でオペレーションするようにユーザーを制限する方法について説明します。

RBAC 認証

Kubernetes 1.6 以降を実行している GKE クラスタでは、個々のクラスタでユーザーに実行を許可する機能に関してさらに制限を加えることができます。Cloud IAM はユーザーにクラスタとその中のすべてのリソースへのアクセス権を提供できますが、Kubernetes の役割ベースのアクセス制御(RBAC)により、Kubernetes API を使用して、ユーザーがクラスタ内で実行できるアクションをさらに制限できます。

RBAC により、クラスタ管理者は、クラスタ内の個々の名前空間またはクラスタ全体に詳細なポリシーを適用します。Kubernetes コマンドライン インターフェース kubectl は、gcloud ツールからのアクティブな資格情報を使用して、クラスタ管理者が RoleBindings のサブジェクトとして GCP ID(ユーザーやサービス アカウント)に役割をマップできるようにします。

たとえば、下の図では、user-auser-b の 2 人のユーザーがいて、これらのユーザーには、app-a 名前空間への config-readerpod-reader の役割が付与されています。

RBAC 認証

別の例として、特定のユーザーにプロジェクト内のすべてのクラスタへのアクセス権を付与する GCP プロジェクト レベルの IAM の役割があります。さらに、特定のクラスタや名前空間内のリソースに対する粒度の細かいアクセス権を付与する RBAC によって、個々の名前空間およびクラスタレベルの役割バインディングが追加されます。

IAM 役割バインディング

Kubernetes にはデフォルトの役割がいくつか含まれていますが、クラスタ管理者は組織のニーズにより密接に対応する独自の役割を作成できます。以下は、delete 動詞が含まれていないため、ユーザーが ConfigMaps を表示、編集、更新のみ可能で、削除することはできない役割の例です。

kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  namespace: default
  name: config-editor
rules:
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: ["get", "list", "watch", "create", "update", "patch"]

役割を定義したら、バインディングによって、クラスタまたは名前空間にこれらの役割を適用できます。バインディングは、役割をユーザー、グループ、またはサービス アカウントに関連付けます。以下は、以前に作成した役割(config-editor)と bob@example.org ユーザーおよび development 名前空間とのバインディング例です。

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: config-editors
  namespace: development
subjects:
- kind: User
  name: bob@example.org
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: config-editor
  apiGroup: rbac.authorization.k8s.io

RBAC の詳細については、GKE のドキュメントをご覧ください。

イメージのアクセスと共有

Container Registry のイメージは、Cloud Storage に格納されています。このセクションでは、イメージを共有する 2 つの方法について説明します。1 つはイメージを公開すること、もう 1 つはプロジェクト間でイメージを共有することです。

イメージの公開

イメージを保持するオブジェクトとバケットを公開することによって、イメージを公開できます。詳細な手順については、Container Registry のアクセス制御のドキュメントを参照してください。

プロジェクト間でのイメージへのアクセス

Kubernetes ノードにサービス アカウントを使用させることで、プロジェクト間でコンテナ イメージを共有できます。プロジェクトに関連付けられるデフォルトのサービス アカウントの形式は [PROJECT_ID]-compute@developer.gserviceaccount.com です。この識別子を用意したら、Container Registry を使用するプロジェクトに対し、storage.viewer としてアクセス権を付与できます。ただし、デフォルトでプロジェクト全体に対するエディタ アクセス権が割り当てられるため、権限が制限されたカスタム サービス アカウントを使用します。

クラスタに別のサービス アカウントを使用するには、クラスタまたはノードプールの作成時に --service-account フラグを使用してサービス アカウントを指定します。たとえば、プロジェクト my-project で gke-sa サービス アカウントを使用するには、次のように指定します。

gcloud container clusters create west --service-account \
  gke-sa@my-project.google.com.iam.gserviceaccount.com

ネットワークの構成

Kubernetes は、クラスタ内の一連のポッド間に加えて、クラスタ外で実行されているレガシー システムに対しても、負荷分散とサービス検出を提供するサービス抽象化を行います。以下のセクションでは、Kubernetes ポッドと他の Kubernetes クラスタを含む他のシステム間の通信のベスト プラクティスについて説明します。

同じクラスタ内の通信

サービス ディスカバリ

Kubernetes では、一連のラベルに基づいて、クラスタ内で実行されているポッドをグループ化するサービスを定義できます。DNS を使用して、このポッドのグループをクラスタ内で検出できます。Kubernetes のサービス検出の詳細については、アプリケーションとサービスの接続に関するドキュメントをご覧ください。

DNS

クラスタローカルの DNS サーバー kube-dns が各 GKE クラスタにデプロイされ、サービス名と正常なポッド IP とのマッピングを処理します。デフォルトで、Kubernetes DNS サーバーはサービスのクラスタ IP アドレスを返します。この IP アドレスは、サービスの存続期間を通じて静的です。この IP にトラフィックを送信すると、ノード上の iptables は、サービスのセレクタに一致する準備完了状態のポッド全体でパケットを負荷分散します。これらの iptables は、各ノードで実行する kube-proxy サービスによって自動的にプログラムされます。

サービス検出と稼働状況モニタリングが必要な場合でも、DNS サービスで仮想 IP の代わりにポッドの IP が返されるようにするには、ClusterIP フィールドを「None」に設定して、サービスをプロビジョニングできます。これにより、サービスがヘッドレスになります。この場合、DNS サーバーが返すのは、サービスで定義されたラベルセレクタに一致する準備完了状態のポッドの A レコードにサービスの DNS 名をマップする A レコードのリストです。レスポンス内のレコードがローテーションし、さまざまなポッド間への負荷の分散を容易にします。一部のクライアント側 DNS リゾルバは DNS レスポンスをキャッシュに保存するため、A レコードのローテーションが無効になることがあります。ClusterIP を使用する利点は、Kubernetes のドキュメントに示されています。

ヘッドレス サービスの典型的な使用例の 1 つは、StatefulSets です。StatefulSets は、レプリカ間の安定したストレージとネットワークを必要とするステートフルなアプリケーションを実行する場合に適しています。このタイプのデプロイでは、安定したネットワーク ID を持つポッドをプロビジョニングします。つまり、クラスタ内でホスト名を解決できます。ポッドの IP は変更される可能性がありますが、そのホスト名 DNS エントリは最新の状態に維持されて、解決可能になります。

パケットフロー: ClusterIP

次の図は、標準 Kubernetes サービスの DNS レスポンスとパケットフローを示しています。ポッド IP アドレスはクラスタ外からルーティング可能ですが、サービスのクラスタ IP はクラスタ内でのみアクセス可能です。これらの仮想 IP アドレスは、各 Kubernetes ノードで宛先ネットワーク アドレス変換(DNAT)を行うことによって実装されます。各ノードで実行されている kube-proxy サービスが、クラスタ IP アドレスをクラスタ全体の正常なポッド IP アドレスにマップする転送ルールを、各ノードで最新の状態に維持します。ローカルノードで実行中のサービスのポッドがある場合はそのポッドが使用され、ない場合はクラスタ内のランダムポッドが選択されます。

クラスタ IP サービス

サービス IP の実装方法について詳しくは、Kubernetes のドキュメントをご覧ください。GKE のネットワーキングの詳細については、YouTube の Next 2017 の講演をご覧ください。

ヘッドレス サービス

以下は、ヘッドレス サービスの DNS レスポンスとトラフィック パターンの例です。ポッド IP アドレスは、デフォルトの GCP サブネットワーク ルートテーブルによってルーティング可能であり、アプリケーションから直接アクセスされます。

ヘッドレス サービスの DNS レスポンスとトラフィック パターンの例

ネットワーク ポリシー

Kubernetes Engine のネットワーク ポリシーの適用を使用すると、クラスタのポッドとサービス間の通信を制御できます。Kubernetes Engine でネットワーク ポリシーを定義するには、Kubernetes ネットワーク ポリシー API を使用してポッドレベルのファイアウォール ルールを作成します。これらのファイアウォール ルールは、クラスタ内でどのポッドとどのサービスが互いにアクセスできるかを決定します。

ネットワーク ポリシーは、クラスタで実行されているワークロードのセキュリティを強化する、一種の深層防御です。たとえば、アプリケーション内の不正使用されたフロントエンド サービスが数レベル下の課金サービスや会計サービスと直接通信できないようにするネットワーク ポリシーを作成できます。

ネットワーク ポリシーを使用して、異なるテナントに属するワークロードを分離することもできます。たとえば、テナント単位の名前空間モデルを定義して、セキュアなマルチテナンシーを提供できます。このようなモデルでは、ネットワーク ポリシー ルールにより、特定の名前空間内のポッドやサービスが異なる名前空間内の他のポッドやサービスにアクセスできないようにすることができます。

ネットワーク ポリシーの詳細については、GKE のドキュメントをご覧ください。

Google Cloud Platform の内部から GKE クラスタに接続する

クラスタの外部から(ただし GCP ネットワークのプライベート IP 空間内から)サービスに接続するには、内部負荷分散を使用します。Kubernetes 内でサービスを作成するときに type: Load Balancercloud.google.com/load-balancer-type: Internal アノテーションを指定すると、GCP プロジェクト内に内部ネットワーク ロードバランサが作成され、TCP および UDP トラフィックをポッド間で分散するように構成されます。

クラスタ内から外部サービスへの接続

多くの場合、Kubernetes 内で実行しているアプリケーションを、クラスタの外部にあるサービス、データベース、アプリケーションと接続する必要があります。下記の 3 つのオプションがあります。

スタブドメイン

Kubernetes 1.6 以降では、特定のドメインの DNS クエリを外部 DNS サーバーに転送するようにクラスタ内部 DNS サービス(kube-dns)を構成できます。これは、Kubernetes ポッドが使用する必要があるドメインについて、クエリを実行する優先 DNS サーバーがある場合に便利です。

外部ネームサービス

外部ネームサービスを使用すると、DNS レコードをクラスタ内のサービス名にマップできます。この場合、クラスタ内サービスの DNS ルックアップでは、選択した CNAME レコードが返されます。既存の DNS サービスにマップするレコードが少ない場合は、これを使用するとよいでしょう。

セレクタのないサービス

セレクタなしでサービスを作成し、エンドポイントをそれに手動で追加して、サービス検出に正しい値を設定できます。これにより、クラスタ内サービスに対して同じサービス検出メカニズムを使用して、DNS によるサービス検出がないシステムにも確実に到達できるようにします。このアプローチは最も柔軟性がありますが、長期的に最も構成とメンテナンスを必要とします。

DNS の詳細については、Kubernetes DNS ポッドおよびサービスのドキュメント ページを参照してください。

インターネットからクラスタへのトラフィックを受信する

インターネットからトラフィックを Kubernetes で実行されているサービスに送信するには、ネットワーク負荷分散または HTTP(s) 負荷分散という 2 つの方法を使用できます。

Kubernetes サービスは、外部 TCP / UDP 負荷分散のための LoadBalancer タイプとして作成する必要があります。Kubernetes は GCP プロジェクト内にネットワーク ロードバランサを作成し、それを Kubernetes Engine クラスタのノードにマップします。これは、最小構成で TCP および UDP ワークロードの負荷分散を行う簡単な方法です。ネットワーク ロードバランサはリージョンで範囲指定されているため、同じリージョン内で実行しているポッドに対してのみトラフィックを分散できます。

us-west1 リージョンでのネットワーク ロードバランサ

HTTP(S) 負荷分散の場合は、単一のエニーキャスト IP アドレスを使用して複数のリージョンにトラフィックを負荷分散できる Google のグローバル HTTP(S) ロードバランサを利用する必要があります。Kubernetes では、ホスト名とパスをクラスタ内のサービスにマップできる受信リソースを作成できます。正しい受信動作にするためには、type: NodePort を指定してサービスが作成されている必要があります。

複数リージョンにわたる負荷分散

ファイアウォール

GKE ノードは Compute Engine にインスタンスとしてプロビジョニングされます。そのため、他のインスタンスと同じステートフルなファイアウォール メカニズムに従います。これらのファイアウォール ルールはタグを使用して、ネットワーク内でインスタンスに適用されます。各ノードプールは、ルールで使用できる独自のタグセットを受け取ります。デフォルトでは、ノードプールに属する各インスタンスは、このノードプールが属する特定の Kubernetes Engine クラスタを識別するタグを受け取ります。このタグは、Kubernetes Engine が自動的に作成するファイアウォール ルールで使用されます。クラスタまたはノードプールの作成時に、gcloud コマンドラインで --tags フラグを使用して、独自のカスタムタグを追加できます。

たとえば、内部ロードバランサがすべてのノードのポート 8080 にアクセスできるようにするには、次のコマンドを使用します。

gcloud compute firewall-rules create \
  allow-8080-fwr --target-tags allow-8080 --allow tcp:8080 \
  --network gke --source-range 130.211.0.0/22
gcloud container clusters create my-cluster --tags allow-8080

次の例では、あるクラスタにタグを付けてインターネット トラフィックがポート 30000 上のノードにアクセスできるようにする一方、他のクラスタには VPN からポート 40000 へのトラフィックを許可するタグを付けています。これは、VPN などの特権ネットワークを使用してのみ、会社のデータセンターにアクセスできるようにするか、プロジェクト内の別のクラスタからアクセスできるようにする必要のあるサービスを NodePort によって公開する場合に便利です。

2 つのクラスタに異なるタグを付ける

オンプレミスのデータセンターへの接続

オンプレミスのデータセンターへの接続には、いくつかの Cloud Interconnect オプションを使用できます。これらのオプションは相互に排他的ではないため、ワークロードと要件に基づいて組み合わせることができます。

  1. 大量のデータを使用することがなく、レイテンシの影響も大きくないワークロード用にインターネット。Google は世界各地のサービス プロバイダに 100 を超える PoP(接続拠点)を提供しています。
  2. 専用の帯域幅を必要とし、レイテンシの影響が大きく、GCP の全プロダクトを含むすべての Google サービスにアクセスする必要があるワークロード用のダイレクト ピアリング。ダイレクト ピアリングは BGP ルートの交換によって行われるレイヤ 3 接続であるため、登録済みの ASN が必要です。
  3. Carrier Interconnect はダイレクト ピアリングと同じですが、サービス プロバイダを通じて行われます。これは、登録済みの ASN がない場合や、優先するサービス プロバイダとの既存の関係がある場合に適したオプションです。
  4. Cloud VPN は、IPsec 暗号化が必要な場合、またはプライベート ネットワークをプライベート Compute Engine ネットワークに拡張する場合に、レイヤ 3 相互接続とインターネット オプション(1、2、3)で構成します。

次のステップ

このページは役立ちましたか?評価をお願いいたします。

フィードバックを送信...