マルチクラスタ設定でのユーザー クラスタの作成

ベアメタル上の Anthos クラスタでは、ユーザー クラスタがワークロードを実行します。マルチクラスタ アーキテクチャでは、ユーザー クラスタの作成と管理は管理クラスタによって行われます。

管理クラスタを作成したら、bmctl create config コマンドを呼び出し、ユーザー クラスタを定義する yaml ファイルを作成します。次に、kubectl コマンドを使用してその構成を適用して、ユーザー クラスタを作成できます。

ワークロードを管理クラスタ以外に配置すると、管理クラスタに保存されている SSH 認証鍵などの重要な管理情報は、その情報を必要としないユーザーから保護されます。さらに、ユーザー クラスタを互いに分離しておくことで、ワークロードの全般的なセキュリティを維持できます。

要件

  • gs://anthos-baremetal-release/bmctl/1.6.2/linux-amd64/bmctl からダウンロードした bmctl
  • クラスタ API サーバー(controlPlaneVIP)にアクセスできる作業用の管理クラスタがある
  • 管理クラスタノードは、ターゲット ユーザー クラスタ上のすべてのノードとネットワークで接続されている必要がある
  • ユーザー クラスタ内のすべてのノードで、root ユーザーまたは SUDO ユーザーとして使用できるユーザー クラスタの作成に使用できる SSH 認証鍵がある

ユーザー クラスタ構成ファイルを作成する

ユーザー クラスタを作成するための構成ファイルは、管理クラスタの作成に使用される構成ファイルとほぼ同じです。唯一の違いは、ローカルの認証情報構成セクションを削除し、構成ファイルを Kubernetes リソースの有効なコレクションにすることです。構成セクションは、ファイルの先頭にある bmctl configuration variables セクションの下にあります。

デフォルトでは、ユーザー クラスタはその管理クラスタから認証情報を継承します。これらの認証情報の一部またはすべてを無効にできます。詳しくは、ユーザー クラスタ構成ファイルの例をご覧ください。

以下の手順では、構成ファイルの編集を再度確認してください。kubectl コマンドでユーザー クラスタを作成しているため、ユーザー クラスタ構成上のプリフライト チェックに制限があります。

  1. 次の bmctl create config コマンドを使用して、ユーザー クラスタ構成ファイルを作成します。

    bmctl create config -c USER_CLUSTER_NAME
    

    たとえば、user1 というユーザー クラスタの構成ファイルを作成するには、次のコマンドを実行します。

    bmctl create config -c user1
    

    ファイルは bmctl-workspace/user1/user1.yaml に書き込まれます。このファイルへの一般的なパスは bmctl-workspace/CLUSTER NAME/CLUSTER_NAME.yaml です。

  2. 構成ファイルに次の変更を行います。

    • ローカルの認証情報ファイル パスを構成から削除します。このファイル パスはユーザー クラスタには必要なく、kubectl コマンドで機能しません。次の項目を削除します。
      ....
        gcrKeyPath: {path to GCR service account key}
        sshPrivateKeyPath: (path to SSH private key, used for node access)
        gkeConnectAgentServiceAccountKeyPath: (path to Connect agent service account key)
        gkeConnectRegisterServiceAccountKeyPath: (path to Hub registration service account key)
        cloudOperationsServiceAccountKeyPath: (path to Cloud Operations service account key)
      ....
            
    • 構成を変更して、クラスタタイプを admin ではなく user を指定します。
      ....
      spec:
        # Cluster type. This can be:
        #   1) admin:  to create an admin cluster. This can later be used to create
        #   user clusters.
        #   2) user:   to create a user cluster. Requires an existing admin cluster.
        #   3) hybrid: to create a hybrid cluster that runs admin cluster
        #   components and user workloads.
        #   4) standalone: to create a cluster that manages itself, runs user
        #   workloads, but does not manage other clusters.
        type: user
      ....
      
    • ロードバランサの VIP とアドレスプールに対する管理クラスタとユーザー クラスタの指定が補完され、既存のクラスタと重複しないことを確認します。以下に、負荷分散とアドレスプールを指定する管理クラスタとユーザー クラスタの構成のサンプルを示します。
    • ....
      # Sample admin cluster config for load balancer and address pools
        loadBalancer:
          vips:
            controlPlaneVIP: 10.200.0.49
            ingressVIP: 10.200.0.50
          addressPools:
          - name: pool1
            addresses:
            - 10.200.0.50-10.200.0.70
      ....
      ....
      # Sample user cluster config for load balancer and address pools
      loadBalancer:
          vips:
            controlPlaneVIP: 10.200.0.71
            ingressVIP: 10.200.0.72
          addressPools:
          - name: pool1
            addresses:
            - 10.200.0.72-10.200.0.90
      ....
      

      ユーザー クラスタ構成ファイルの残りの部分は管理クラスタ構成ファイルと同じです。

  3. ユーザー クラスタ構成ファイルを再確認します。ユーザー クラスタ作成時、ベアメタル上の Anthos クラスタのプリフライト チェックには制限があり、マシンレベルのチェック(OS バージョン、ソフトウェア バージョンの競合、使用可能なリソースなど)のみが対象となります。

ユーザー クラスタを作成する

kubectl コマンドを実行して、ユーザー クラスタ構成ファイルを適用し、クラスタを作成します。

kubectl --kubeconfig ADMIN_KUBECONFIG apply -f USER_CLUSTER_CONFIG

ADMIN_KUBECONFIG には、管理クラスタの kubeconfig ファイルのパスを指定します。USER_CLUSTER_CONFIG には、前のセクションで編集したユーザー クラスタの YAML ファイルのパスを指定します。

たとえば、admin という名前の管理クラスタと user1 という名前のユーザー クラスタの構成の場合、コマンドは次のようになります。

kubectl --kubeconfig bmctl-workspace/admin/admin-kubeconfig apply /
  -f bmctl-workspace/user1/user1.yaml

ユーザー クラスタの準備が完了するまで待機する

ユーザー クラスタの準備ができていることを確認するには、kubectl wait コマンドを使用して状態をテストします。以下のコマンドでは、クラスタの状態の調整が完了したことを確認するために 30 分間待機し、作成されたユーザー クラスタ kubeconfig ファイルを取得します。

kubectl --kubeconfig ADMIN_KUBECONFIG wait \
  cluster USER_CLUSTER_NAME -n cluster-USER_CLUSTER_NAME \
  --for=condition=Reconciling=False --timeout=30m && \
  kubectl --kubeconfig ADMIN_KUBECONFIG get secret USER_CLUSTER_NAME-kubeconfig \
  -n cluster-USER_CLUSTER_NAME \
  -o 'jsonpath={.data.value}' | base64 -d > USER_KUBECONFIG

ここで

  • ADMIN_KUBECONFIG には、管理クラスタの kubeconfig ファイルのパスを指定します。
  • USER_KUBECONFIG は、作成するユーザー kubeconfig ファイルのパスを指定します。
  • USER_CLUSTER_NAME は、ユーザー クラスタの名前です。

たとえば、admin という名前の管理クラスタと user1 という名前のユーザー クラスタの構成の場合、コマンドは次のようになります。

kubectl --kubeconfig bmctl-workspace/admin/admin-kubeconfig wait  \
  cluster user1 -n cluster-user1 --for=condition=Reconciling=False --timeout=30m &&  \
  kubectl --kubeconfig bmctl-workspace/admin/admin-kubeconfig get secret  \
  user1-kubeconfig -n cluster-user1 -o 'jsonpath={.data.value}' | base64  \
  -d > bmctl-workspace/user1/user1-kubeconfig

ワーカー ノードプールの準備が完了するまで待機する

多くの場合、ワーカー ノードプールの準備が完了するまで待機する必要もあります。通常、ユーザー クラスタでワークロードを実行するために、ワーカー ノードプールを使用します。

ワーカー ノードプールの準備ができていることを確認するには、kubectl wait コマンドを使用して状態をテストします。この場合、このコマンドは、ノードプールの準備ができるまで再度 30 分間待機します。

kubectl --kubeconfig ADMIN_KUBECONFIG wait cluster USER_CLUSTER_NAME \
  -n cluster-USER_CLUSTER_NAME --for=condition=Reconciling=False --timeout=30m && \
  kubectl --kubeconfig ADMIN_KUBECONFIG wait nodepool NODE_POOL_NAME \
  -n cluster-USER_CLUSTER_NAME --for=condition=Reconciling=False --timeout=30m && \
  kubectl --kubeconfig ADMIN_KUBECONFIG get secret \
  USER_CLUSTER_NAME-kubeconfig -n cluster-USER_CLUSTER_NAME -o \
  'jsonpath={.data.value}' | base64 -d >  USER_KUBECONFIG
  

NODE_POOL_NAME は、ユーザー クラスタを使用して作成するノードプールを指定します。

たとえば、admin という名前の管理クラスタ、user1 という名前のユーザー クラスタ構成ファイル、node-pool-1 という名前のノードプールの場合、コマンドは次のようになります。

kubectl --kubeconfig bmctl-workspace/admin/admin-kubeconfig wait \
  cluster user1 -n cluster-user1 --for=condition=Reconciling=False --timeout=30m && \
  kubectl --kubeconfig bmctl-workspace/admin/admin-kubeconfig wait \
  nodepool node-pool-1 -n cluster-user1 --for=condition=Reconciling=False --timeout=30m && \
  kubectl --kubeconfig bmctl-workspace/admin/admin-kubeconfig get secret \
  user1-kubeconfig -n cluster-user1 -o \
  'jsonpath={.data.value}' | base64 -d > bmctl-workspace/user1/user1-kubeconfig

完全なユーザー クラスタ構成ファイルのサンプル

次に、bmctl コマンドによって作成されたユーザー クラスタ構成ファイルの例を示します。このサンプル構成では、プレースホルダのクラスタ名、VIP、アドレスが使用されていることに注意してください。ネットワークによっては動作しない可能性があります。

# Sample user cluster config:

apiVersion: v1
kind: Namespace
metadata:
  name: cluster-user1
---
apiVersion: baremetal.cluster.gke.io/v1
kind: Cluster
metadata:
  name: user1
  namespace: cluster-user1
spec:
  # Cluster type. This can be:
  #   1) admin:  to create an admin cluster. This can later be used to create user clusters.
  #   2) user:   to create a user cluster. Requires an existing admin cluster.
  #   3) hybrid: to create a hybrid cluster that runs admin cluster components and user workloads.
  #   4) standalone: to create a cluster that manages itself, runs user workloads,
  #   but does not manage other clusters.
  type: user
  # Anthos cluster version.
  anthosBareMetalVersion: 1.6.2
  # GKE connect configuration
  gkeConnect:
    projectID: GOOGLE_PROJECT_ID
    # To override default credentials inherited from the admin cluster:
    # 1. Create a new secret in the admin cluster
    # 2. Uncomment the section below and refer to the secret created above
    # # Optionally override default secret inherited from the admin cluster.
    # connectServiceAccountSecret:
    #  name: GKE_CONNECT_AGENT_SA_SECRET
    #  namespace: cluster-user1
    # # Optionally override default secret inherited from the admin cluster.
    # registerServiceAccountSecret:
    #  name: GKE_CONNECT_REGISTER_SA_SECRET
    #  namespace: cluster-user1
  # Control plane configuration
  controlPlane:
    nodePoolSpec:
      nodes:
      # Control plane node pools. Typically, this is either a single machine
      # or 3 machines if using a high availability deployment.
      - address: 10.200.0.4
  # Cluster networking configuration
  clusterNetwork:
    # Pods specify the IP ranges from which Pod networks are allocated.
    pods:
      cidrBlocks:
      - 192.168.0.0/16
    # Services specify the network ranges from which service VIPs are allocated.
    # This can be any RFC 1918 range that does not conflict with any other IP range
    # in the cluster and node pool resources.
    services:
      cidrBlocks:
      - 10.96.0.0/12
  # Credentials specify the secrets that hold SSH key and image pull credential for the new cluster.
  # credentials:
  #  # Optionally override default ssh key secret inherited from the admin cluster.
  #  sshKeySecret:
  #    name: SSH_KEY_SECRET
  #    namespace: cluster-user1
  #  # Optionally override default image pull secret inherited from the admin cluster.
  #  imagePullSecret:
  #    name: IMAGE_PULL_SECRET
  #    namespace: cluster-user1
  # Load balancer configuration
  loadBalancer:
    # Load balancer mode can be either 'bundled' or 'manual'.
    # In 'bundled' mode a load balancer will be installed on load balancer nodes during cluster creation.
    # In 'manual' mode the cluster relies on a manually-configured external load balancer.
    mode: bundled
    # Load balancer port configuration
    ports:
      # Specifies the port the LB serves the kubernetes control plane on.
      # In 'manual' mode the external load balancer must be listening on this port.
      controlPlaneLBPort: 443
    # There are two load balancer VIPs: one for the control plane and one for the L7 Ingress
    # service. The VIPs must be in the same subnet as the load balancer nodes.
    vips:
      # ControlPlaneVIP specifies the VIP to connect to the Kubernetes API server.
      # This address must not be in the address pools below.
      controlPlaneVIP: 10.200.0.71
      # IngressVIP specifies the VIP shared by all services for ingress traffic.
      # Allowed only in non-admin clusters.
      # This address must be in the address pools below.
      ingressVIP: 10.200.0.72
    # AddressPools is a list of non-overlapping IP ranges for the data plane load balancer.
    # All addresses must be in the same subnet as the load balancer nodes.
    # Address pool configuration is only valid for 'bundled' LB mode in non-admin clusters.
    addressPools:
    - name: pool1
      addresses:
      # Each address must be either in the CIDR form (1.2.3.0/24)
      # or range form (1.2.3.1-1.2.3.5).
      - 10.200.0.72-10.200.0.90
    # A load balancer nodepool can be configured to specify nodes used for load balancing.
    # These nodes are part of the kubernetes cluster and run regular workloads as well as load balancers.
    # If the node pool config is absent then the control plane nodes are used.
    # Node pool configuration is only valid for 'bundled' LB mode.
    # nodePoolSpec:
    #  nodes:
    #  - address: 
  # Proxy configuration
  # proxy:
  #   url: http://[username:password@]domain
  #   # A list of IPs, hostnames or domains that should not be proxied.
  #   noProxy:
  #   - 127.0.0.1
  #   - localhost
  # Logging and Monitoring
  clusterOperations:
    # Cloud project for logs and metrics.
    projectID: $GOOGLE_PROJECT_ID
    # Cloud location for logs and metrics.
    location: us-central1
    # Optionally override default secret inherited from the admin cluster.
    # serviceAccountSecret:
    #  name: $CLOUD_OPERATIONS_SA_SECRET
    #  namespace: cluster-user1
    # Whether collection of application logs/metrics should be enabled (in addition to
    # collection of system logs/metrics which correspond to system components such as
    # Kubernetes control plane or cluster management agents).
    # enableApplication: false
  # Storage configuration
  storage:
    # lvpNodeMounts specifies the config for local PersistentVolumes backed by mounted disks.
    # These disks need to be formatted and mounted by the user, which can be done before or after
    # cluster creation.
    lvpNodeMounts:
      # path specifies the host machine path where mounted disks will be discovered and a local PV
      # will be created for each mount.
      path: /mnt/localpv-disk
      # storageClassName specifies the StorageClass that PVs will be created with. The StorageClass
      # is created during cluster creation.
      storageClassName: local-disks
    # lvpShare specifies the config for local PersistentVolumes backed by subdirectories in a shared filesystem.
    # These subdirectories are automatically created during cluster creation.
    lvpShare:
      # path specifies the host machine path where subdirectories will be created on each host. A local PV
      # will be created for each subdirectory.
      path: /mnt/localpv-share
      # storageClassName specifies the StorageClass that PVs will be created with. The StorageClass
      # is created during cluster creation.
      storageClassName: local-shared
      # numPVUnderSharedPath specifies the number of subdirectories to create under path.
      numPVUnderSharedPath: 5
  # Authentication; uncomment this section if you wish to enable authentication to the cluster with OpenID Connect.
  # authentication:
  #   oidc:
  #     # issuerURL specifies the URL of your OpenID provider, such as "https://accounts.google.com". The Kubernetes API
  #     # server uses this URL to discover public keys for verifying tokens. Must use HTTPS.
  #     issuerURL: 
  #     # clientID specifies the ID for the client application that makes authentication requests to the OpenID
  #     # provider.
  #     clientID: 
  #     # clientSecret specifies the secret for the client application.
  #     clientSecret: 
  #     # kubectlRedirectURL specifies the redirect URL (required) for the gcloud CLI, such as
  #     # "http://localhost:[PORT]/callback".
  #     kubectlRedirectURL: <Redirect URL for the gcloud CLI; optional, default is "http://kubectl.redirect.invalid">
  #     # username specifies the JWT claim to use as the username. The default is "sub", which is expected to be a
  #     # unique identifier of the end user.
  #     username: <JWT claim to use as the username; optional, default is "sub">
  #     # usernamePrefix specifies the prefix prepended to username claims to prevent clashes with existing names.
  #     usernamePrefix: 

  #     # group specifies the JWT claim that the provider will use to return your security groups.
  #     group: 
  #     # groupPrefix specifies the prefix prepended to group claims to prevent clashes with existing names.
  #     groupPrefix: 

  #     # scopes specifies additional scopes to send to the OpenID provider as a comma-delimited list.
  #     scopes: 
  #     # extraParams specifies additional key-value parameters to send to the OpenID provider as a comma-delimited
  #     # list.
  #     extraParams: 
  #     # certificateAuthorityData specifies a Base64 PEM-encoded certificate authority certificate of your identity
  #     # provider. It's not needed if your identity provider's certificate was issued by a well-known public CA.
  #     certificateAuthorityData: 
  # Node access configuration; uncomment this section if you wish to use a non-root user
  # with passwordless sudo capability for machine login.
  # nodeAccess:
  #   loginUser: 
---
# Node pools for worker nodes
apiVersion: baremetal.cluster.gke.io/v1
kind: NodePool
metadata:
  name: node-pool-1
  namespace: cluster-user1
spec:
  clusterName: user1
  nodes:
  - address: 10.200.0.5