При добавлении компонентов Kubernetes в облачный шаблон Cloud Assembly можно добавить кластеры или разрешить пользователям создавать пространства имен в различных конфигурациях. Как правило, выбор операции зависит от требований по контролю доступа, от способа настройки компонентов Kubernetes и требований к развертыванию.

Чтобы добавить компонент Kubernetes в облачный шаблон в Cloud Assembly, выберите Проектирование > Облачные шаблоны, щелкните Создать, а затем найдите и разверните параметр Kubernetes в меню слева. Затем выберите нужный вариант («Кластер» или «Пространство имен KBS»), перетащив его на холст.

Добавление кластера Kubernetes, связанного с проектом, в облачный шаблон — это наиболее простой способ предоставить соответствующим пользователям доступ к ресурсам Kubernetes. Для управления местом развертывания можно использовать теги в кластерах, так же как в случае с другими ресурсами Cloud Assembly. Теги можно использовать для выбора зоны и плана VMware Tanzu Kubernetes Grid Integrated Edition (TKGI) на этапе выделения в ходе развертывания кластера.

После добавления кластера таким образом он автоматически становится доступен всем допустимым пользователям.

Примеры облачных шаблонов

В первом примере показан облачный шаблон для простого развертывания Kubernetes, управляемого с помощью тегов. Зона Kubernetes создана с двумя планами развертывания, настроенными на странице «Создать зону Kubernetes». В этом случае тег с именем placement:tag добавлен в зону как возможность, и он используется для сопоставления аналогичного ограничения в облачном шаблоне. Если тег присвоен нескольким зонам, будет выбрано значение с наименьшим приоритетом.

formatVersion: 1
inputs: {}
resources:
  Cluster_provisioned_from_tag:
    type: Cloud.K8S.Cluster
    properties:
      hostname: 109.129.209.125
      constraints:
	-tag: 'placement tag'
      port: 7003
      workers: 1
      connectBy: hostname 

Во втором примере облачного шаблона показано, как настроить шаблон с переменной $(input.hostname), чтобы пользователи могли ввести требуемое имя узла кластера при запросе развертывания. Теги также можно использовать для выбора зоны и плана TKGI на этапе выделения ресурсов в ходе развертывания кластера.

formatVersion: 1
inputs:
  hostname:
    type: string
    title: Cluster hostname
resources:
  Cloud_K8S_Cluster_1:
    type: Cloud.K8S.Cluster
    properties:
      hostname: ${input.hostname}
      port: 8443
      connectBy: hostname
      workers: 1

Если необходимо использовать пространства имен для управления использованием кластера, в облачном шаблоне можно настроить переменную name: ${input.name} для подстановки имени пространства имен, вводимого пользователем при запросе развертывания. Для развертывания такого типа необходимо создать облачный шаблон, как в примере ниже.

1 formatVersion: 1
2 inputs:
3 name:
4    type: string
5    title: "Namespace name"
6 resources:
7    Cloud_KBS_Namespace_1:
8        type: Cloud.K8S.Namespace
9        properties:
10            name: ${input.name}

Пользователи могут управлять развернутыми кластерами с помощью файлов kubeconfig, доступных на странице Инфраструктура > Ресурсы > Кластеры Kubernetes. Найдите карточку на странице для нужного кластера и нажмите Kubeconfig.

Пространства имен управляющей программы в шаблонах VMware Cloud Templates

Ниже приведена схема для основного пространства имен управляющей программы в облачном шаблоне Cloud Assembly.

{
  "title": "Supervisor namespace schema",
  "description": "Request schema for provisioning of Supervisor namespace resource",
  "type": "object",
  "properties": {
    "name": {
      "title": "Name",
      "description": "Alphabetic (a-z and 0-9) string with maximum length of 63 characters. The character ‘-’ is allowed anywhere except the first or last position of the identifier.",
      "type": "string",
      "pattern": "^.*\\$\\{.*\\}.*$|^((?!-)[a-z0-9-]{1,63}(?<!-))$",
      "ignoreOnUpdate": true
    },
    "description": {
      "title": "Description",
      "description": "An optional description of this Supervisor namespace.",
      "type": "string",
      "ignoreOnUpdate": true
    },
    "content": {
      "title": "Content",
      "description": "Kubernetes Yaml Content",
      "type": "string",
      "maxLength": 65000
    },
    "constraints": {
      "title": "Constraints",
      "description": "To target the correct resources, blueprint constraints are matched against infrastructure capability tags. Constraints must include the key name. Options include value, negative [!], and hard or soft requirement.",
      "type": "array",
      "recreateOnUpdate": true,
      "items": {
        "type": "object",
        "properties": {
          "tag": {
            "title": "Tag",
            "description": "Constraint definition in syntax `[!]tag_key[:tag_value][:hard|:soft]` \nExamples:\n```\n!location:eu:hard\n location:us:soft\n!pci\n```",
            "type": "string",
            "recreateOnUpdate": true
          }
        }
      }
    },
    "limits": {
      "title": "Limits",
      "description": "Defines namespace resource limits such as pods, services, etc.",
      "type": "object",
      "properties": {
        "stateful_set_count": {
          "title": "stateful_set_count",
          "description": "This represents the new value for 'statefulSetCount' option which is the maximum number of StatefulSets in the namespace.",
          "type": "integer",
          "recreateOnUpdate": false
        },
        "deployment_count": {
          "title": "deployment_count",
          "description": "This represents the new value for 'deploymentCount' option which is the maximum number of deployments in the namespace.",
          "type": "integer",
          "recreateOnUpdate": false
        },
        "cpu_limit_default": {
          "title": "cpu_limit_default",
          "description": "This represents the new value for the default CPU limit (in Mhz) for containers in the pod. If specified, this limit should be at least 10 MHz.",
          "type": "integer",
          "recreateOnUpdate": false
        },
        "config_map_count": {
          "title": "config_map_count",
          "description": "This represents the new value for 'configMapCount' option which is the maximum number of ConfigMaps in the namespace.",
          "type": "integer",
          "recreateOnUpdate": false
        },
        "pod_count": {
          "title": "pod_count",
          "description": "This represents the new value for 'podCount' option which is the maximum number of pods in the namespace.",
          "type": "integer",
          "recreateOnUpdate": false
        },
        "job_count": {
          "title": "job_count",
          "description": "This represents the new value for 'jobCount' option which is the maximum number of jobs in the namespace.",
          "type": "integer",
          "recreateOnUpdate": false
        },
        "secret_count": {
          "title": "secret_count",
          "description": "This represents the new value for 'secretCount' option which is the maximum number of secrets in the namespace.",
          "type": "integer",
          "recreateOnUpdate": false
        },
        "cpu_limit": {
          "title": "cpu_limit",
          "description": "This represents the new value for 'limits.cpu' option which is equivalent to the maximum CPU limit (in MHz) across all pods in the namespace.",
          "type": "integer",
          "recreateOnUpdate": false
        },
        "cpu_request_default": {
          "title": "cpu_request_default",
          "description": "This represents the new value for the default CPU request (in Mhz) for containers in the pod. If specified, this field should be at least 10 MHz.",
          "type": "integer",
          "recreateOnUpdate": false
        },
        "memory_limit_default": {
          "title": "memory_limit_default",
          "description": "This represents the new value for the default memory limit (in mebibytes) for containers in the pod.",
         "type": "integer",
          "recreateOnUpdate": false
        },
        "memory_limit": {
          "title": "memory_limit",
          "description": "This represents the new value for 'limits.memory' option which is equivalent to the maximum memory limit (in mebibytes) across all pods in the namespace.",
          "type": "integer",
          "recreateOnUpdate": false
        },
        "memory_request_default": {
          "title": "memory_request_default",
          "description": "This represents the new value for the default memory request (in mebibytes) for containers in the pod.",
          "type": "integer",
          "recreateOnUpdate": false
        },
        "service_count": {
          "title": "service_count",
          "description": "This represents the new value for 'serviceCount' option which is the maximum number of services in the namespace.",
          "type": "integer",
          "recreateOnUpdate": false
        },
        "replica_set_count": {
          "title": "replica_set_count",
          "description": "This represents the new value for 'replicaSetCount' option which is the maximum number of ReplicaSets in the namespace.",
          "type": "integer",
          "recreateOnUpdate": false
        },
        "replication_controller_count": {
          "title": "replication_controller_count",
          "description": "This represents the new value for 'replicationControllerCount' option which is the maximum number of ReplicationControllers in the namespace.",
          "type": "integer",
          "recreateOnUpdate": false
        },
        "storage_request_limit": {
          "title": "storage_request_limit",
          "description": "This represents the new value for 'requests.storage' which is the limit on storage requests (in mebibytes) across all persistent volume claims from pods in the namespace.",
          "type": "integer",
          "recreateOnUpdate": false
        },
        "persistent_volume_claim_count": {
          "title": "persistent_volume_claim_count",
          "description": "This represents the new value for 'persistentVolumeClaimCount' option which is the maximum number of PersistentVolumeClaims in the namespace.",
          "type": "integer",
          "recreateOnUpdate": false
        },
        "daemon_set_count": {
          "title": "daemon_set_count",
          "description": "This represents the new value for 'daemonSetCount' option which is the maximum number of DaemonSets in the namespace.",
          "type": "integer",
          "recreateOnUpdate": false
        }
      },
      "additionalProperties": false
    },
    "vm_classes": {
      "title": "VM classes",
      "description": "Defines set of Virtual Machine classes to be assigned to the namespace",
      "type": "array",
      "recreateOnUpdate": false,
      "items": {
        "type": "object",
        "properties": {
          "name": {
            "title": "Name",
            "description": "Name of the Virtual Machine class.",
            "type": "string",
            "recreateOnUpdate": false
          }
        }
      }
    },
    "storage": {
      "title": "Storage policies",
      "description": "Defines set of storage profiles to be used to assign storage policies to the namespace.",
      "type": "array",
      "recreateOnUpdate": false,
      "items": {
        "type": "object",
        "properties": {
          "profile": {
            "type": "object",
            "title": "Storage profile",
            "description": "Defines storage policies to be assigned to the namespace",
            "recreateOnUpdate": false,
            "properties": {
              "constraints": {
                "title": "Constraints",
                "description": "To target the correct storage profiles, blueprint constraints are matched against storage profile capability tags.",
                "type": "array",
                "recreateOnUpdate": false,
                "items": {
                  "type": "object",
                  "properties": {
                    "tag": {
                      "title": "Tag",
                      "description": "Constraint definition in syntax `[!]tag_key[:tag_value][:hard|:soft]` \nExamples:\n```\nlocation:eu:hard\n location:us:soft\n```",
                      "type": "string",
                      "recreateOnUpdate": false
                    }
                  }
                },
                "minItems":1
              },
              "limitMb": {
                "title": "Limit",
                "description": "The maximum amount of storage (in mebibytes) which can be utilized by the namespace for this storage policy. Optional. If unset, no limits are placed.",
                "type": "integer"
              }
            },
            "required": [
              "constraints"
            ]
          }
        }
      }
    }
  },
  "required": [
    "name"
  ]
}

Шаблоны VMware Cloud Templates поддерживают использование предельных значений для пространств имен управляющей программы. Предельные значения позволяют контролировать использование ресурсов ЦП и памяти, а также максимальное количество модулей, разрешенных в пространстве имен, в зависимости от числа развернутых компьютеров.

formatVersion: 1
inputs: {}
resources:
  Cloud_SV_Namespace_1:
    type: Cloud.SV.Namespace
    properties:
      name: '${env.deploymentName}'
      limits:
        - cpu_limit: 1000
          cpu_request_default: 800
          memory_limit: 2000
          memory_limit_default: 1500
          pod_count: 200

В следующем примере показано, как можно указать политику хранилища с помощью тегов.

formatVersion: 1
inputs: {}
resources:
  Cloud_SV_Namespace_1:
    type: Cloud.SV.Namespace
    properties:
      name: 'ns-with-storage-policy'
      description: 'sample'
      storage: 
        - profile: 
            limitMb: 1000
            constraints: 
              - tag: 'storage:fast'
        - profile: 
            constraints: 
              - tag: 'storage:cheap'

Использование произвольных кодов YAML с пространством имен самообслуживания или VCT кластера

В ходе создания кластера или пространства имен пользователям часто требуется выполнить дополнительную настройку. Например, может потребоваться добавление пользователей (привязки «роль — роль»), создание политики безопасности модуля или установка агентов. С помощью свойства YAML content пользователи могут определить настраиваемые пакеты, которые нужно подготовить в данном пространстве имен кластера или управляющей программы.

Каждый пакет содержимого YAML, связанный со свойством content, должен быть отделен тройным тире (---). Сведения о содержимом должны представлять собой строку с несколькими подстроками. Дополнительные сведения о настройке пакетов содержимого см. в следующем примере кода YAML.

formatVersion: 1
inputs: {}
resources:
  Cloud_Tanzu_Cluster_1:
    type: Cloud.Tanzu.Cluster
    properties:
      name: ddonchev-tkc
      plan: small
      content: |-
        apiVersion: rbac.authorization.k8s.io/v1
        kind: ClusterRoleBinding
        metadata:
          name: psp:authenticated-from-yaml
        subjects:
        - apiGroup: rbac.authorization.k8s.io
          kind: Group
          name: system:authenticated
        roleRef:
          apiGroup: rbac.authorization.k8s.io
          kind: ClusterRole
          name: psp:vmware-system-privileged
        ---
        apiVersion: apiextensions.k8s.io/v1
        kind: CustomResourceDefinition
        metadata:
          # name must match the spec fields below, and be in the form: <plural>.<group>
          name: crontabs.stable.example.com
        spec:
          # group name to use for REST API: /apis/<group>/<version>
          group: stable.example.com
          # list of versions supported by this CustomResourceDefinition
          versions:
            - name: v1
              # Each version can be enabled/disabled by Served flag.
              served: true
              # One and only one version must be marked as the storage version.
              storage: true
              schema:
                openAPIV3Schema:
                  type: object
                  properties:
                    spec:
                      type: object
                      properties:
                        cronSpec:
                          type: string
                        image:
                          type: string
                        replicas:
                          type: integer
          # either Namespaced or Cluster
          scope: Namespaced
          names:
            # plural name to be used in the URL: /apis/<group>/<version>/<plural>
            plural: crontabs
            # singular name to be used as an alias on the CLI and for display
            singular: crontab
            # kind is normally the CamelCased singular type. Your resource manifests use this.
            kind: CronTab
            # shortNames allow shorter string to match your resource on the CLI
            shortNames:
            - ct

Код YAML, определенный в свойстве содержимого, также отображается на вкладке «Свойства» для развертывания.

Cloud Assembly может создавать ресурсы содержимого только в пределах развертываемого ресурса. Например, при подготовке пространства имен kubernetes Cloud Assembly не может создать развертывание в другом пространстве имен. Пользователи имеют те же права, как если бы они использовали kubeconfig с kubectl.

После подготовки виртуальной машины начнется процесс установки объектов kubernetes внутри свойства content. Если не удастся подготовить один из ресурсов, ссылки на которые содержатся в свойстве содержимого YAML, Cloud Assembly выполнит откат и удалит из ресурса все предыдущие объекты kubernetes, а развертывание будет иметь состояние «Ошибка». Этот ресурс будет по-прежнему подготовлен и будет отображаться. Также можно использовать действия по регулярному обслуживанию, в том числе попытаться повторно применить содержимое.

Для расширения свойства content можно использовать входные данные из облачного шаблона, как показано в следующем примере.

formatVersion: 1
inputs: {}
resources:
  Cloud_SV_Namespace_1:
    type: Cloud.SV.Namespace
    properties:
      name: sv-namespace-with-vm-classes
      vm_classes:
        - name: best-effort-2xlarge
        - name: best-effort-4xlarge
        - name: best-effort-8xlarge

Кроме того, можно подготовить настраиваемые ресурсы, например TanzuKubernetesCluster. Это действие, представляющее собой операцию в ходе настройки, завершится сбоем, так как пространство имен управляющей программы не будет содержать необходимые классы виртуальной машины и классы хранилища. Если классы виртуальной машины и классы хранилища привязаны к пространству имен управляющей программы, то TanzuKubernetesCluster (или другой ресурс) можно создать с помощью действия по регулярному обслуживанию.

Примечание. Ресурс можно подготовить без содержимого. Объекты kubernetes в виде кода YAML можно будет пр-прежнему добавить с помощью действия по регулярному обслуживанию.

Содержимое, отображаемое в свойстве YAML, определяет, что именно подготовлено в ресурсе. В следующей таблице показаны возможные результаты в случае изменения этого содержимого.

Действие Результат
Если добавляется объект kubernetes и выполняется отправка. Указанный объект создается в ресурсе.
Если удаляется объект kubernetes и выполняется отправка. Указанный объект удаляется из ресурса.
Если изменяется объект kubernetes и выполняется отправка. Указанный объект исправляется в ресурсе.

Важно пояснить, какие действия считаются изменением текущего объекта. Например, если изменить поле пространства имен для объекта, то вместо исправления старого объекта будет создан новый объект.

Уникальность ресурса определяется следующими полями: apiVersion, kind, metadata.name, metadata.namespace.