Ao adicionar componentes do Kubernetes a um modelo de nuvem do Cloud Assembly, você pode optar por adicionar clusters ou permitir que os usuários criem namespaces em várias configurações. Normalmente, essa escolha depende dos seus requisitos de controle de acesso, de como você configurou seus componentes do Kubernetes e dos seus requisitos de implantação.

Para adicionar um componente do Kubernetes a um modelo de nuvem no Cloud Assembly, clique em Design > Modelos de Nuvem, clique em Novo e localize e expanda a opção Kubernetes no menu à esquerda. Em seguida, faça a seleção desejada, Cluster ou Namespace KBS, arrastando-a até a tela.

Adicionar um cluster do Kubernetes associado a um projeto até um modelo de nuvem é o método mais simples de disponibilizar recursos do Kubernetes para usuários válidos. Você pode usar tags em clusters para controlar onde eles são implantados, como você faz com outros recursos do Cloud Assembly. É possível usar tags para selecionar uma zona e um plano do VMware Tanzu Kubernetes Grid Integrated Edition (TKGI) durante a fase de alocação da implantação do cluster.

Ao adicionar um cluster dessa maneira, ele é disponibilizado automaticamente para todos os usuários válidos.

Exemplos de modelos de nuvem

O primeiro exemplo de modelo de nuvem mostra um modelo para uma implantação simples do Kubernetes que é controlada por marcação. Uma zona do Kubernetes foi criada com dois planos de implantação, configurados na página Nova Zona do Kubernetes. Nesse caso, uma tag chamada placement:tag foi adicionada como recurso na zona e foi usada para corresponder à restrição análoga no modelo de nuvem. Se houver mais de uma zona configurada com a tag, aquela com o número de prioridade mais baixa será selecionada.

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 

Os segundo exemplo de modelo de nuvem mostra como configurar um modelo com uma variável chamada $(input.hostname), para que os usuários possam inserir o nome do host do cluster desejado ao solicitar uma implantação. Tags também podem ser usadas para selecionar uma zona e um plano do TKGI durante a fase de alocação de recursos da implantação do cluster.

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

Se quiser usar namespaces para gerenciar o uso do cluster, você poderá configurar uma variável no modelo de nuvem chamada name: ${input.name} para substituir o nome do namespace que um usuário insere ao solicitar uma implantação. Para esse tipo de implantação, crie um modelo semelhante ao exemplo a seguir:

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}

Os usuários podem gerenciar clusters implantados por meio de arquivos kubeconfig acessíveis na página Infraestrutura > Recursos > Clusters do Kubernetes. Localize o cartão na página para o cluster desejado e clique em Kubeconfig.

Namespaces de Supervisor em VMware Cloud Templates

Veja a seguir o esquema para um namespace de supervisor básico em um modelo de nuvem do 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"
  ]
}

Os VMware Cloud Templates oferecem suporte ao uso de limites com namespaces de supervisor. Os limites permitem que você controle o uso de recursos para CPUs e memória, bem como o número máximo de pods permitidos no namespace por máquinas implantadas.

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

O exemplo a seguir mostra como você pode especificar uma política de armazenamento usando tags.

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'

Usando YAMLs arbitrários com VCTs de cluster ou namespace de autoatendimento

Como parte da criação de um cluster ou namespace, os usuários geralmente desejam executar personalizações adicionais. Por exemplo, você pode querer adicionar usuários (associação de função/ função) ou criar uma política de segurança de pod ou instalar agentes. Usando a propriedade YAML content, os usuários podem definir pacotes personalizados que desejam provisionar nesse cluster/namespace /namespace de supervisor.

Cada pacote de conteúdo YAML associado à propriedade content deve ser separado com um traço triplo (---). Além disso, as informações de conteúdo devem ser uma cadeia de caracteres de várias linhas. Consulte o exemplo YAML a seguir para ver como os pacotes de conteúdo podem ser configurados.

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

O YAML definido na propriedade de conteúdo também aparece na guia Propriedades da implantação.

O Cloud Assembly apenas pode criar recursos de conteúdo no escopo do recurso que está sendo implantado. Por exemplo: se você provisionar um namespace do Kubernetes, o Cloud Assembly não poderá criar uma implantação dentro de um namespace diferente. Os usuários têm os mesmos direitos como se estivessem usando o kubeconfig com kubectl.

Depois que a máquina virtual for provisionada, uma instalação dos objetos Kubernetes dentro da propriedade content será iniciada. Se o provisionamento de um dos recursos referenciados na propriedade de conteúdo YAML falhar, o Cloud Assembly reverterá e excluirá todos os objetos Kubernetes anteriores desse recurso, e a implantação terá um status de Falha. O recurso ainda estará provisionado e visível. Além disso, você ainda pode usar ações de dia 2, incluindo tentar aplicar o conteúdo novamente.

Você pode aprimorar a propriedade content com entradas do modelo de nuvem, como mostra o exemplo a seguir.

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

Além disso, você pode provisionar recursos personalizados, como TanzuKubernetesCluster. Isso falharia como uma operação de dia 1, pois o namespace do supervisor não conterá as classes de máquina virtual e as classes de armazenamento necessárias. Quando as classes de máquina virtual e as classes de armazenamento estão vinculadas ao namespace de supervisor, você pode criar TanzuKubernetesCluster (ou outro recurso) usando a ação de dia 2.

Observação: você pode provisionar um recurso sem conteúdo e ainda poderá adicionar objetos Kubernetes como YAML com a ação de dia 2.

O conteúdo que aparece na propriedade YAML define o que é provisionado no recurso. Quando você edita esse conteúdo, a tabela a seguir mostra os resultados possíveis:

Ação Resultado
Se adicionar um objeto Kubernetes e enviar. O objeto especificado é criado no recurso.
Se remover um objeto Kubernetes e enviar. O objeto especificado é excluído do recurso.
Se modificar um objeto Kubernetes e enviar. O objeto especificado é corrigido no recurso.

É importante esclarecer quais ações são consideradas como uma modificação no objeto atual. Por exemplo: se você modificar o campo de namespace de um objeto, um novo objeto será criado no lugar do antigo que está sendo corrigido.

A exclusividade de um recurso é definida pelos seguintes campos: apiVersion, kind, metadata.name e metadata.namespace