マルチテナント対応の Kubernetes クラスターを構成する: パート 1

Kubernetes は、コンテナー化されたアプリケーションのデプロイ、スケーリング、管理の自動化を目的としたオープンソース・システムです。開発者たちの間では、コンテナー化されたワークロードとサービスを管理するためのコンテナー・オーケストレーション・プラットフォームとして盛んに使われています。通常、ワークロードを起動するための Kubernetes クラスターは、ローカルでプロビジョニングすることも、パブリック・クラウド・プロバイダーを介して作成することもできます。例えば、IBM Cloud Kubernetes Service を利用すれば、簡単に Kubernetes クラスターを取得できます。

スタンドアロンの Kubernetes クラスターでは、組織で必要とする分離レベルを達成できない場合もあります。例えば、複数の社内チームとクラウド上のさまざまなサービスが関わってくるとしたら、ノイズ、競合、セキュリティーに関するあらゆる問題を回避できるようなビジネス部門間の分離が必要になります。1 つの選択肢として、複数のクラスターを起動すれば、各チームを厳格に分離することができます。けれども、それにはかなりのコストがかかります。また、共通の内部サービスを複数の Kubernetes クラスター間で共有するのは簡単なことではありません。もう 1 つの選択肢は、1 つの Kubernetes クラスターをテナント間で共有することです。幸い、Kubernetes には複数の分離機能が備わっていて、1 つの Kubernetes クラスター上で複数のテナントをサポートできるようになっています。

このチュートリアルでは、マルチテナント対応の Kubernetes クラスターを構成する方法を紹介します。チュートリアルで取り上げるサンプルは、IBM Cloud Kubernetes Service をベースとしています。

チュートリアルに取り組む前に、Kubernetes で テナント という言葉が持つ意味を理解する必要があります。

テナントは、Kubernetes ユーザーのグループを表します。テナントには Kubernetes クラスター内で所定のリソース・グループにアクセスする権限がありますが、必要な権限がなければ他のリソースにはアクセスできません。Kubernetes クラスター内のリソースは、テナントによって分離されます。テナントにより、Kubernetes クラスター内で使用できるリソースの量を制限する特定のクォータを割り当てることができます。また、テナントの管理者は、他のテナント・ユーザーのリソース・グループに対する権限を管理できます。

Kubernetes には、マルチテナントの要件を満たすために利用できるさまざまな機能があります。例えば、Kubernetes の名前空間を使用することで、他の Kubernetes リソース (ポッド、デプロイメント、サービスなど) をグループ化できます。また、役割ベースのアクセス制御 (RBAC) を使用すれば、Kubernetes リソースに対する特定の役割を定義できます。その役割をターゲット・ユーザーにバインドすると、関連するリソースに対する権限をユーザーに付与できます。ネットワーク・ポリシーを定義して、名前空間のインバウンド・トラフィックとアウトバンド・トラフィックを制御することもできます。さらに、Kubernetes のリソース・クォータを構成して、名前空間ごとのリソース使用量を制御することもできます。

前提条件

このチュートリアルの手順に取り組むための準備として、以下のタスクを行う必要があります。

所要時間

このチュートリアルの手順を最初から最後まで完了するには、約 1 時間かかります。

Kubernetes クラスター上に複数のテナントをセットアップするための手順

以下の手順では IBM Cloud Kubernetes クラスターを例に、マルチテナント対応のクラスターを構成する方法を説明します。

  1. IBM Cloud コンソールを使用して、multiple-tenants-cluster という名前の IBM Cloud Kubernetes クラスターをプロビジョニングします。それには、「IBM Cloud Kubernetes Service 概説」で説明している手順を参照してください。このチュートリアルではユーザー sam@company.com がクラスターを作成することを前提とします。Sam はクラスター全体の管理者であり、クラスターに対してあらゆる操作を実行する権限があります。権限について詳しくは、「RBAC 役割ごとの Kubernetes リソース許可」 (admin と cluster-admin の列) を参照してください。

  2. クラスターを作成すると、IBM Cloud Kubernetes Service によって自動的にクラスター役割バインディング ibm-admin が作成されます。このバインディングにより、クラスターの作成者 sam@company.comcluster-admin という特定のクラスター役割が割り当てられます。これにより、sam@company.com はクラスター管理者として、このクラスター内のテナントを管理することになります。cluster-adminClusterRole 定義を確認するには、以下のコマンドを使用します。

    >> kubectl get clusterrole cluster-admin -o yaml
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      ......
      name: cluster-admin
    rules:
    - apiGroups:
      - '*'
      resources:
      - '*'
      verbs:
      - '*'
    - nonResourceURLs:
      - '*'
      verbs:
      - '*'
    
  3. ClusterRoleBinding 定義から、現在のクラスター管理者の権限をリストアップします。

     >> kubectl get clusterrolebinding ibm-admin -o yaml
     apiVersion: rbac.authorization.k8s.io/v1
     kind: ClusterRoleBinding
     metadata:
     ......
     name: admin
     roleRef:
     apiGroup: rbac.authorization.k8s.io
     kind: ClusterRole
     name: cluster-admin
     subjects:
     - apiGroup: rbac.authorization.k8s.io
     kind: User
     name: IAM#sam@company.com
    
  4. クラスター管理者 sam@company.com が、コマンド kubectl create namespace group-1 を使用して group-1 という名前空間を作成します。以下のセクションでは、この group-1 名前空間をテナントの Kubernetes リソース・グループとして扱います。

  5. (省略可) クラスター管理者 sam@company.com はリソース不足を防ぐために、妥当なリソース・クォータを別のテナントに割り当てることができます。

    group-1 の例を確認するには、以下のコマンドを実行してください。当然ながら、仕様の数値は要件とクラスターのワーカー・ノードのサイズに応じて構成できます。

     cat << EOF | kubectl apply -f -
     ---
     apiVersion: v1
     kind: ResourceQuota
     metadata:
       name: compute-resources
       namespace: group-1
     spec:
       hard:
         pods: "2"
         requests.cpu: "1"
         requests.memory: 1Gi
         limits.cpu: "2"
         limits.memory: 2Gi
         requests.nvidia.com/gpu: 4
     EOF
    
  6. このステップと次のステップでは、クラスター管理者 sam@company.comgroup-1 名前空間を管理するテナント管理者として jan@company.com という別のユーザーを追加しようとしていることを前提とします。

    まず、sam@company.comjan@company.com を IBM Cloud Kubernetes Service にオンボーディングする必要があります。これにより、jan@company.com に、kubectl コマンドを実行する前にクラスターの kubeconfig ファイルをダウンロードするための適切な権限を付与できるようになります。「コンソールを使用した IBM Cloud IAM 役割の割り当て」で説明している手順に従って、Platform access -- viewer 権限を追加します。

    IBM Cloud ユーザー・インターフェースを使用するか、以下のコマンドを実行します。

     ibmcloud account user-invite jan@company.com
     ibmcloud iam user-policy-create jan@company.com --roles Viewer --service-name containers-kubernetes
    

    これで、jan@company.comibmcloud cs cluster config --cluster <cluster-name> コマンドを実行してクラスター構成をダウンロードできるようになります。

  7. これで、クラスター管理者 sam@company.com はテナント管理者権限を jan@company.com に付与するために、選択した名前空間に対する admin 役割に Jan のユーザー ID をバインドできるようになりました。

     cat << EOF | kubectl apply -f -
     ---
     apiVersion: rbac.authorization.k8s.io/v1
     kind: RoleBinding
     metadata:
       name: tenant-admin
       namespace: group-1
     subjects:
     - kind: User
       name: IAM#jan@company.com
       apiGroup: rbac.authorization.k8s.io
     roleRef:
       kind: ClusterRole
       name: admin
       apiGroup: rbac.authorization.k8s.io
     EOF
    

    詳細な設定を確認したい場合は、kubectl get clusterrole admin -o yaml を実行します。これにより、admin の役割定義が返されます。

    ここまでのところで、jan@company.comgroup-1 名前空間の管理者になったものの、他の名前空間にはアクセスできません。

  8. このステップでは、クラスター管理者 sam@company.com が別のユーザー tom@company.comgroup-1 名前空間のテナント・ユーザーとしてクラスターに追加します。

    前の手順と同じように、sam@company.com は IAM Platform access -- viewer 権限を tom@company.com に付与する必要があります。

    IBM Cloud Kubernetes Service では、edit という役割が事前定義されています。名前空間内でアプリケーションをデプロイするテナント・ユーザーに、この役割を使用できます。edit の詳細な設定に興味がある場合、kubectl get clusterrole edit -o yaml コマンドを実行すると、この役割の定義を確認できます。

    前の手順で jan@company.comgroup-1 名前空間のテナント管理者の役割を付与したので、jan@company.com がクラスターにログインして、group-1 名前空間のテナント・ユーザーとして tom@company.com を追加できます。

     cat << EOF | kubectl apply -f -
     ---
     apiVersion: rbac.authorization.k8s.io/v1
     kind: RoleBinding
     metadata:
       name: tenant-user
       namespace: group-1
     subjects:
     - kind: User
       name: IAM#tom@company.com
       apiGroup: rbac.authorization.k8s.io
     roleRef:
       kind: ClusterRole
       name: edit
       apiGroup: rbac.authorization.k8s.io
     EOF
    

    これで、tom@company.com は他の名前空間にはアクセスできなくても、group-1 にはログインして、この名前空間内にアプリケーションをデプロイできるようになりました。

マルチテナントに応じたネットワークを構成するための手順

1 つのクラスターを複数のテナントが共有する場合、それぞれのテナント管理者が独自の名前空間内だけにサービスの使用を制限し、他の名前空間からのアクセスを拒否することが要件となる可能性があります。

この要件を実装するには、Kubernetes のネットワーク・ポリシーを使用します。Kubernetes ドキュメントの「Network Policies」を参照してください。

以下の例では、テナント管理者の Jan が名前空間に対するネットワーク・ポリシーを構成します。このネットワーク・ポリシーで、kube-system を除くすべての名前空間からのアクセスを拒否します。唯一アクセスが許可されるこの名前空間は、IBM Cloud Kubernetes Service 内の多数のシステム・ポットをホストするシステム名前空間です。したがって、Ingress を介したアプリケーションの外部アクセスを公開できるよう、kube-system のアクセスを許可する必要があります (Jan のようなテナント管理者は、「Network Policies」で説明している手順に従って、group-1 名前空間に対する他のネットワーク・ポリシーを追加で定義することもできます)。

  1. kube-systemnamespace: system のラベルを付けます。

     >> kubectl edit namespace kube-sytem
     apiVersion: v1
     kind: Namespace
     metadata:
       ......
       labels:
         namespace: system
        name: kube-system
     spec:
       finalizers:
       - kubernetes
     status:
       phase: Active
    
  2. namespace:system ラベル付きの名前空間からのアクセスのみを許可する、group-1 名前空間に対するネットワーク・ポリシーを作成します。

     cat << EOF | kubectl apply -f -
     ---
     kind: NetworkPolicy
     apiVersion: networking.k8s.io/v1
     metadata:
       namespace: group-1
       name: deny-from-other-namespaces
     spec:
       podSelector: {}
       ingress:
       - from:
         - podSelector: {}
         - namespaceSelector:
             matchLabels:
               namespace: system
     EOF
    

まとめ

このチュートリアルの手順に従う中で、Kubernetes では 1 つの Kubernetes クラスター上に複数のテナントを実装する際に役立つ、名前空間、役割ベースのアクセス制御、リソース・クォータ、ネットワーク・ポリシーといった機能を使用できることを確認できたはずです。これらの機能を利用すれば、複数のテナント間の正しいレベルの分離と正しいレベルのリソース共有を実現できます。現在、Kubernetes コミュニティーではマルチテナント対応を目的とした機能を他にも開発中です。最新情報を入手するには、Kubernetes Multi-tenancy Special Interest Group コミュニティー (kubernetes-sigs/multi-tenancy community) にアクセスしてください。

このチュートリアル・シリーズの第 2 回で、マルチテナント対応の Kubernetes クラスターをモニタリングする方法を学んでください。