사용자 지정 ClusterClass를 기반으로 TKG 클러스터를 프로비저닝하려면 다음 지침을 참조하십시오. 이러한 지침은 vSphere 8 U1 환경에만 적용됩니다.

사전 요구 사항

사용자 지정 ClusterClass를 기반으로 TKG 클러스터를 프로비저닝하는 절차는 vSphere 8 U1 릴리스부터 사용할 수 있습니다. vSphere 8 U2를 사용하는 경우 v1beta1 예: 사용자 지정 ClusterClass 기반 클러스터(vSphere 8 U2 이상 워크플로) 항목을 참조하십시오.

다음 사전 요구 사항을 준수합니다.
  • vSphere 8 U1 환경
  • 워크로드 관리 사용
  • 감독자 구성됨
  • vSphere에 대한 Kubernetes CLI 도구가 설치된 Ubuntu 클라이언트
주의: 사용자 지정 ClusterClass는 업스트림 클러스터 API 설명서에 따른 실험적인 Kubernetes 기능입니다. 사용자 지정 ClusterClass에서 사용할 수 있는 사용자 지정 범위로 인해 VMware 가능한 모든 사용자 지정을 테스트하거나 검증할 수 없습니다. 고객은 사용자 지정 ClusterClass 클러스터를 테스트, 검증 및 문제 해결해야 합니다. 고객은 사용자 지정 ClusterClass 클러스터와 관련된 지원 티켓을 열 수 있습니다. 다만, VMware 지원 팀이 최선의 노력을 기울이더라도, 사용자 지정 ClusterClass 클러스터에 대해 열린 모든 문제에 대한 해결을 보장할 수는 없습니다. 운영 환경에서 사용자 지정 ClusterClass 클러스터를 배포하기 전에 고객은 이러한 위험을 알고 있어야 합니다.

1부: 사용자 지정 ClusterClass 생성

첫 번째 부분에는 이름이 tanzukubernetescluster인 기본 ClusterClass를 복제하여 사용자 지정 ClusterClass를 생성하는 작업이 포함됩니다.
  1. 이름이 custom-nsvSphere 네임스페이스를 생성합니다.
  2. 감독자에 로그인합니다.
  3. 컨텍스트를 이름이 custom-nsvSphere 네임스페이스로 전환합니다.
  4. 기본 ClusterClass를 가져옵니다.
    kubectl get clusterclass tanzukubernetescluster -o json
  5. 기본 ClusterClass를 복제하여 이름이 custom-cc인 사용자 지정 ClusterClass를 생성합니다.
    kubectl get clusterclass tanzukubernetescluster -o json | jq '.metadata.name="custom-cc"' | kubectl apply -f -
    예상 결과:
    clusterclass.cluster.x-k8s.io/custom-cc created
  6. 사용자 지정 ClusterClass를 가져옵니다.
    kubectl get clusterclass custom-cc -o json

    필요한 경우 를 적게 사용하여 사용자 지정 ClusterClass를 볼 수 있습니다.

    kubectl get clusterclass custom-cc -o json | less
    참고: "q" 명령을 실행하여 더 적게 종료합니다.

2부: TKG 클러스터를 프로비저닝하는 데 필요한 감독자 개체 생성

다음 부분은 사용자 지정 ClusterClass를 사용하여 사용자 지정 TKG 클러스터의 초기 배포에 필요한 감독자 개체를 생성하는 것입니다.
참고: 기본적으로 클러스터 이름 "ccc-cluster"를 사용합니다. 다른 클러스터 이름을 사용하는 경우 적절한 필드를 변경해야 합니다.
  1. 자체 서명된 확장 인증서에 대한 발급자를 생성합니다.
    #self-signed-extensions-issuer.yaml
    apiVersion: cert-manager.io/v1
    kind: Issuer
    metadata:
      name: self-signed-extensions-issuer
    spec:
      selfSigned: {}
    kubectl apply -f self-signed-extensions-issuer.yaml -n custom-ns
    예상 결과:
    issuer.cert-manager.io/self-signed-extensions-issuer created
  2. 확장 CA 인증서에 대한 암호를 생성합니다.
    #extensions-ca-certificate.yaml
    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
      name: ccc-cluster-extensions-ca
    spec:
      commonName: kubernetes-extensions
      duration: 87600h0m0s
      isCA: true
      issuerRef:
        kind: Issuer
        name: self-signed-extensions-issuer
      secretName: ccc-cluster-extensions-ca
      usages:
      - digital signature
      - cert sign
      - crl sign
    kubectl apply -f extensions-ca-certificate.yaml -n custom-ns
    예상 결과:
    certificate.cert-manager.io/ccc-cluster-extensions-ca created
  3. 확장 CA 인증서에 대한 발급자를 생성합니다.
    #extensions-ca-issuer.yaml
    apiVersion: cert-manager.io/v1
    kind: Issuer
    metadata:
      name: ccc-cluster-extensions-ca-issuer
    spec:
      ca:
        secretName: ccc-cluster-extensions-ca
    kubectl apply -f extensions-ca-issuer.yaml -n custom-ns
    예상 결과:
    issuer.cert-manager.io/ccc-cluster-extensions-ca-issuer created
  4. 인증 서비스 인증서에 대한 암호를 생성합니다.
    #auth-svc-cert.yaml
    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
      name: ccc-cluster-auth-svc-cert
    spec:
      commonName: authsvc
      dnsNames:
      - authsvc
      - localhost
      - 127.0.0.1
      duration: 87600h0m0s
      issuerRef:
        kind: Issuer
        name: ccc-cluster-extensions-ca-issuer
      secretName: ccc-cluster-auth-svc-cert
      usages:
      - server auth
      - digital signature
    kubectl apply -f auth-svc-cert.yaml -n custom-ns
    예상 결과:
    certificate.cert-manager.io/ccc-cluster-auth-svc-cert created
  5. 발급자 및 인증서의 생성을 확인합니다.
    kubectl get issuers -n custom-ns
    NAME                               READY   AGE
    ccc-cluster-extensions-ca-issuer   True    2m57s
    self-signed-extensions-issuer      True    14m
    
    kubectl get certs -n custom-ns
    NAME                        READY   SECRET                      AGE
    ccc-cluster-auth-svc-cert   True    ccc-cluster-auth-svc-cert   34s
    ccc-cluster-extensions-ca   True    ccc-cluster-extensions-ca   5m
    

3부: 사용자 지정 ClusterClass를 기반으로 TKG 클러스터 생성

Cluster v1beta1 API를 사용하여 ClusterClass를 기반으로 클러스터를 생성합니다. 사용자 지정 ClusterClass를 기준으로 하는 v1beta1 클러스터에는 다음과 같은 최소 변수 집합이 필요합니다.
변수 설명
vmClass TKG 서비스 클러스터에서 VM 클래스 사용의 내용을 참조하십시오.
storageClass vSphere 네임스페이스에 대한 영구 스토리지 구성의 내용을 참조하십시오.
ntp 감독자를 사용하도록 설정하는 데 사용되는 NTP 서버입니다.
extensionCert 이전 섹션에서 "확장 CA 인증서"가 생성된 후 자동으로 생성됩니다.
clusterEncryptionConfigYaml 아래 섹션은 이 파일을 가져오는 프로세스를 안내합니다.
  1. 암호화 암호를 생성합니다.
    #encryption-secret.yaml
    apiVersion: v1
    data:
      key: all3dzZpODFmRmh6MVlJbUtQQktuN2ViQzREbDBQRHlxVk8yYXRxTW9QQT0=
    kind: Secret
    metadata:
      name: ccc-cluster-encryption
    type: Opaque
    kubectl apply -f encryption-secret.yaml -n custom-ns
    예상 결과:
    secret/ccc-cluster-encryption created
  2. 감독자에서 NTP 서버를 수집합니다.
    kubectl -n vmware-system-vmop get configmap vmoperator-network-config -o jsonpath={.data.ntpservers}
  3. 클러스터를 프로비저닝하도록 cluster-with-ccc.yaml 매니페스트를 구성합니다.
    #cluster-with-ccc.yaml
    apiVersion: cluster.x-k8s.io/v1beta1
    kind: Cluster
    metadata:
      name: ccc-cluster
    spec:
      clusterNetwork:
        pods:
          cidrBlocks:
          - 193.0.0.0/16
        serviceDomain: managedcluster1.local
        services:
          cidrBlocks:
          - 198.201.0.0/16
      topology:
        class: custom-cc
        version: v1.26.5---vmware.2-fips.1-tkg.1
        controlPlane:
          metadata: {}
          replicas: 3
        workers:
          machineDeployments:
            - class: node-pool
              metadata: { }
              name: node-pool-workers
              replicas: 3
        variables:
        - name: vmClass
          value: guaranteed-medium
        - name: storageClass
          value: tkg-storage-profile
        - name: ntp
          value: time.acme.com
        - name: extensionCert
          value:
            contentSecret:
              key: tls.crt
              name: ccc-cluster-extensions-ca
        - name: clusterEncryptionConfigYaml
          value: LS0tCm...Ht9Cg==
    클러스터 매니페스트에서 다음 필드를 확인하거나 업데이트합니다.
    매개 변수 설명
    metadata.name v1beta1 클러스터의 이름입니다.
    spec.topology.class 사용자 지정 ClusterClass의 이름입니다.
    spec.topology.version Tanzu Kubernetes 릴리스 버전
    spec.topology.variables.storageClass.value 클러스터가 프로비저닝될 vSphere 네임스페이스에 연결된 StoragePolicy
    spec.topology.variables.ntp.value NTP 서버 주소
    spec.topology.variables.extensionCert.value.contentSecret.name 확인
    spec.topology.variables.clusterEncryptionConfigYaml.value ClusterEncryptionConfig 암호의 data.key 값으로 채웁니다.
  4. 사용자 지정 ClusterClass를 기반으로 클러스터를 생성합니다.
    kubectl apply -f cluster-with-ccc.yaml -n custom-ns
    예상 결과:
    cluster.cluster.x-k8s.io/ccc-cluster created

    vSphere Client를 사용하여 클러스터가 생성되었는지 확인합니다.

  5. TKG 클러스터에 로그인합니다.
    kubectl vsphere login --server=xxx.xxx.xxx.xxx --vsphere-username [email protected] --tanzu-kubernetes-cluster-name ccc-cluster --tanzu-kubernetes-cluster-namespace custom-ns

4부: TKG 클러스터를 관리하는 데 필요한 감독자 개체 생성

CCC가 있는 클러스터가 적용되면 다양한 컨트롤러가 프로비저닝을 시도합니다. 그러나 기본 인프라 리소스에는 여전히 추가 개체를 올바르게 부트스트랩해야 합니다.
매개 변수
인증 인증 값을 수집하고 values.yaml 파일로 업데이트해야 합니다.
Base64로 인코딩됨 values.yaml 파일은 base64 문자열로 인코딩됩니다.
guest-cluster-auth-service-data-values.yaml 이 문자열은 파일을 적용하기 전에 CCC_config_yamls.tar.gz에서 다운로드한 guest-cluster-auth-service-data-values.yaml 파일에 추가됩니다.
GuestClusterAuthSvcDataValues 암호 마지막으로 새로 생성된 GuestClusterAuthSvcDataValues 암호를 참조하도록 게스트 클러스터 부트스트랩을 수정해야 합니다.
  1. 클러스터가 프로비저닝된 vSphere 네임스페이스로 컨텍스트를 전환합니다.
    kubectl config use-context custom-ns
  2. authServicePublicKeys 값을 가져옵니다.
    kubectl -n vmware-system-capw get configmap vc-public-keys -o jsonpath="{.data.vsphere\.local\.json}"
    결과를 이름이 values.yaml인 텍스트 파일에 복사합니다.
    authServicePublicKeys: '{"issuer_url":"https://...SShrDw=="]}]}}'
  3. 클러스터 UID를 가져와서 authServicePublicKeys를 업데이트합니다.
    kubectl get cluster -n custom-ns ccc-cluster -o yaml | grep uid
  4. values.yaml 파일의 authServicePublicKeys 섹션에서 클러스터 UID를 "client_id" 값에 추가합니다.

    구문: vmware-tes:vc:vns:k8s:clusterUID

    예:
    vmware-tes:vc:vns:k8s:7d95b50b-4fd4-4642-82a3-5dbfe87f499c
  5. 인증서 값을 가져옵니다(ccc-cluster를 선택한 클러스터 이름으로 대체).
    kubectl -n custom-ns get secret ccc-cluster-auth-svc-cert -o jsonpath="{.data.tls\.crt}" | base64 -d
  6. 인증서를 values.yaml에 추가합니다.

    authServicePublicKeys 섹션 아래에 인증서 컨텐츠를 추가합니다.

    참고: 실패를 방지하려면 인증서를 4칸 들여써야 합니다.
    예:
    authServicePublicKeys: '{"issuer_url":"https://...SShrDw=="]}]}}'
    ceritificate: |
        -----BEGIN CERTIFICATE-----
        MIIDPTCCAiWgAwIBAgIQMibGSjeuJelQoPxCof/+xzANBgkqhkiG9w0BAQsFADAg
        ...
        sESk/RDTB1UAvi8PD3zcbEKZuRxuo4IAJqFFbAabwULhjUo0UwT+dIJo1gLf5/ep
        VoIRJS7j6VT98WbKyZp5B4I=
        -----END CERTIFICATE-----
  7. privateKey 값을 가져옵니다.
    kubectl -n custom-ns get secret ccc-cluster-auth-svc-cert -o jsonpath="{.data.tls\.key}"
  8. values.yaml 파일을 확인합니다.
    authServicePublicKeys: '{"issuer_url":"https://10.197.79.141/openidconnect/vsphere.local","client_id":"vmware-tes:vc:vns:k8s:7d95...499c",...SShrDw=="]}]}}'
    certificate: |
        -----BEGIN CERTIFICATE-----
        MIIDPTCCAiWgAwIBAgIQWQyXAQDRMhgrGre8ysVN0DANBgkqhkiG9w0BAQsFADAg
        ...
        uJSBP49sF0nKz5nf7w+BdYE=
        -----END CERTIFICATE-----
    privateKey: LS0tLS1CRUdJTi...VktLS0tLQo=
    
  9. base64 인코딩을 사용하여 values.yaml 파일을 해시하여 guest-cluster-auth-service-data-values.yaml 파일에 대한 출력을 수집합니다.
    base64 -i values.yaml -w 0
  10. guest-cluster-auth-service-data-values.yaml 파일을 생성합니다.
    암호에 대한 템플릿은 다음과 같습니다.
    apiVersion: v1
    data:
      values.yaml: YXV0a...ExRbz0K
    kind: Secret
    metadata:
      labels:
        tkg.tanzu.vmware.com/cluster-name: ccc-cluster
        tkg.tanzu.vmware.com/package-name: guest-cluster-auth-service.tanzu.vmware.com.1.3.0+tkg.2-vmware
      name: ccc-cluster-guest-cluster-auth-service-data-values
    type: Opaque
    다음 표를 참조하여 예상되는 암호 값을 채웁니다.
    매개 변수
    data.values.yaml

    Base64로 인코딩된 values.yaml 문자열

    metadata.labels.cluster-name

    클러스터의 이름(예: ccc-cluster)

    metadata.labels.package-name

    guest-cluster-auth-service.tanzu.vmware.com.version

    이 값을 가져오려면 kubectl get tkr v1.26.5---vmware.2-fips.1-tkg.1 -o yaml 명령을 실행합니다

    사용 중인 버전에 따라 TKR 버전을 변경합니다.

    metadata.name

    클러스터의 이름(예: ccc-cluster)

  11. guest-cluster-auth-service-data-values.yaml 암호를 생성합니다.
    kubectl apply -f guest-cluster-auth-service-data-values.yaml -n custom-ns
  12. 암호를 참조하도록 클러스터 부트스트랩을 편집합니다.
    kubectl edit clusterbootstrap ccc-cluster -n custom-ns
  13. guest-cluster-auth-service.tanzu.vmware.com.version: 줄 아래에 다음 줄을 추가합니다.
    valuesFrom:
      secretRef: ccc-cluster-guest-cluster-auth-service-data-values
    예:
    spec:
      additionalPackages:
      - refName: guest-cluster-auth-service.tanzu.vmware.com.1.3.0+tkg.2-vmware
        valuesFrom:
          secretRef: ccc-cluster-guest-cluster-auth-service-data-values
  14. 저장한 후 종료하여 clusterbootstrap 수정 사항을 적용합니다.

5부: 포드 보안 구성

TKR 버전 1.25 이상을 사용하는 경우 이름이 custom-nsvSphere 네임스페이스에 대한 포드 보안을 구성합니다. TKR 1.25 이상에 대한 PSA 구성의 내용을 참조하십시오.

TKR 버전 1.24 이상을 사용하는 경우 클러스터의 포드에는 포드 보안 정책에 대한 바인딩이 필요합니다. 클러스터 수준에서 필요한 리소스 개체를 적용하려면 다음 프로세스를 사용합니다.
  1. TKG 클러스터 kubeconfig를 수집합니다.
    kubectl -n custom-ns get secret ccc-cluster-kubeconfig -o jsonpath="{.data.value}" | base64 -d > ccc-cluster-kubeconfig
  2. psp.yaml 파일을 생성합니다.
    apiVersion: policy/v1beta1
    kind: PodSecurityPolicy
    metadata:
      name: tanzu-system-kapp-ctrl-restricted
    spec:
      privileged: false
      allowPrivilegeEscalation: false
      requiredDropCapabilities:
        - ALL
      volumes:
        - configMap
        - emptyDir
        - projected
        - secret
        - downwardAPI
        - persistentVolumeClaim
      hostNetwork: false
      hostIPC: false
      hostPID: false
      runAsUser:
        rule: MustRunAsNonRoot
      seLinux:
        rule: RunAsAny
      supplementalGroups:
        rule: MustRunAs
        ranges:
          - min: 1
            max: 65535
      fsGroup:
        rule: MustRunAs
        ranges:
          - min: 1
            max: 65535
      readOnlyRootFilesystem: false
  3. 포드 보안 정책을 적용합니다.
    KUBECONFIG=ccc-cluster-kubeconfig kubectl apply -f psp.yaml
  4. TKG 클러스터에 로그인합니다.
    kubectl vsphere login --server=10.197.154.66 --vsphere-username [email protected] --insecure-skip-tls-verify --tanzu-kubernetes-cluster-name ccc-cluster --tanzu-kubernetes-cluster-namespace custom-ns
  5. 네임스페이스를 나열합니다.
    KUBECONFIG=ccc-cluster-kubeconfig kubectl get ns -A
    NAME                           STATUS   AGE
    default                        Active   13d
    kube-node-lease                Active   13d
    kube-public                    Active   13d
    kube-system                    Active   13d
    secretgen-controller           Active   13d
    tkg-system                     Active   13d
    vmware-system-antrea           Active   13d
    vmware-system-cloud-provider   Active   13d
    vmware-system-csi              Active   13d
    vmware-system-tkg              Active   13d
    

6부: vSphere SSO 역할을 사용자 지정 TKG 클러스터와 동기화

개발자가 클러스터 워크로드를 관리할 수 있도록 vSphere 네임스페이스에 구축된 vCenter Single Sign-On 사용자에 대한 Rolebinding을 감독자에서 TKG 클러스터로 동기화해야 합니다.

이 프로세스를 수행하려면 감독자에서 rolebinding 바인딩 목록을 내보내고 "편집" 역할이 있는 rolebinding을 수집하고 sync-cluster-edit-rolebinding.yaml 파일을 생성한 다음, KUBECONFIG를 사용하여 TKG 클러스터에 적용해야 합니다.
  1. 감독자에서 기존 rolebinding을 수집합니다.
    kubectl get rolebinding -n custom-ns  -o yaml
  2. 반환된 rolebinding 개체 목록에서 roleRef.name이 "edit"인 개체를 식별합니다.
    예:
    apiVersion: v1
    items:
    - apiVersion: rbac.authorization.k8s.io/v1
      kind: RoleBinding
      metadata:
        creationTimestamp: "2023-08-25T18:44:45Z"
        name: ccc-cluster-8lr5x-ccm
        namespace: custom-ns
        ownerReferences:
        - apiVersion: vmware.infrastructure.cluster.x-k8s.io/v1beta1
          blockOwnerDeletion: true
          controller: true
          kind: ProviderServiceAccount
          name: ccc-cluster-8lr5x-ccm
          uid: b5fb9f01-9a55-4f69-8673-fadc49012994
        resourceVersion: "108766602"
        uid: eb93efd4-ae56-4d9f-a745-d2782885e7fb
      roleRef:
        apiGroup: rbac.authorization.k8s.io
        kind: Role
        name: ccc-cluster-8lr5x-ccm
      subjects:
      - kind: ServiceAccount
        name: ccc-cluster-8lr5x-ccm
        namespace: custom-ns
    - apiVersion: rbac.authorization.k8s.io/v1
      kind: RoleBinding
      metadata:
        creationTimestamp: "2023-08-25T18:44:45Z"
        name: ccc-cluster-8lr5x-pvcsi
        namespace: custom-ns
        ownerReferences:
        - apiVersion: vmware.infrastructure.cluster.x-k8s.io/v1beta1
          blockOwnerDeletion: true
          controller: true
          kind: ProviderServiceAccount
          name: ccc-cluster-8lr5x-pvcsi
          uid: d9342f8f-13d2-496d-93cb-b24edfacb5c1
        resourceVersion: "108766608"
        uid: fd1820c7-7993-4299-abb7-bb67fb17f1fd
      roleRef:
        apiGroup: rbac.authorization.k8s.io
        kind: Role
        name: ccc-cluster-8lr5x-pvcsi
      subjects:
      - kind: ServiceAccount
        name: ccc-cluster-8lr5x-pvcsi
        namespace: custom-ns
    - apiVersion: rbac.authorization.k8s.io/v1
      kind: RoleBinding
      metadata:
        creationTimestamp: "2023-08-25T16:58:06Z"
        labels:
          managedBy: vSphere
        name: wcp:custom-ns:group:vsphere.local:administrators
        namespace: custom-ns
        resourceVersion: "108714148"
        uid: d74a98c7-e7da-4d71-b1d5-deb60492d429
      roleRef:
        apiGroup: rbac.authorization.k8s.io
        kind: ClusterRole
        name: edit
      subjects:
      - apiGroup: rbac.authorization.k8s.io
        kind: Group
        name: sso:[email protected]
    - apiVersion: rbac.authorization.k8s.io/v1
      kind: RoleBinding
      metadata:
        creationTimestamp: "2023-08-25T16:58:21Z"
        labels:
          managedBy: vSphere
        name: wcp:custom-ns:user:vsphere.local:administrator
        namespace: custom-ns
        resourceVersion: "108714283"
        uid: 07f7dbba-2670-4100-a59b-c09e4b2edd6b
      roleRef:
        apiGroup: rbac.authorization.k8s.io
        kind: ClusterRole
        name: edit
      subjects:
      - apiGroup: rbac.authorization.k8s.io
        kind: User
        name: sso:[email protected]
    kind: List
    metadata:
      resourceVersion: ""
    
  3. sync-cluster-edit-rolebinding.yaml이라는 파일을 생성하여 기본 [email protected] 이외의 추가 rolebinding을 추가합니다. 예:
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      labels:
        run.tanzu.vmware.com/vmware-system-synced-from-supervisor: "yes"
      name: vmware-system-auth-sync-wcp:custom-ns:group:vsphere.local:administrators
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: cluster-admin
    subjects:
    - apiGroup: rbac.authorization.k8s.io
      kind: Group
      name: sso:[email protected]
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      labels:
        run.tanzu.vmware.com/vmware-system-synced-from-supervisor: "yes"
      name: vmware-system-auth-sync-wcp:custom-ns:group:SSODOMAIN.COM:testuser
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: cluster-admin
    subjects:
    - apiGroup: rbac.authorization.k8s.io
      kind: Group
      name: sso:[email protected]
    참고: metadata.name 필드에서 모든 사용자에 대해 사용자 역할 앞에 vmware-system-auth-sync-가 추가됩니다. metadata.name 및 subjects.name 항목은 기본이 아닌 모든 역할을 수정해야 합니다.
  4. sync-cluster-edit-rolebinding.yaml 구성을 적용하여 rolebinding을 동기화합니다.
    KUBECONFIG=ccc-cluster-kubeconfig kubectl apply -f sync-cluster-edit-rolebinding.yaml