你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

Azure 应用程序配置 Kubernetes 提供程序参考

以下参考概述了 Azure 应用配置 Kubernetes 提供程序 v2.1.0 支持的属性。 有关更改的详细信息,请参阅发行说明

属性

AzureAppConfigurationProvider 资源在 spec 下具有以下顶级子属性。 必须指定 endpointconnectionStringReference

名称 说明 必需 类型
endpoint 要从中检索键值的 Azure 应用程序配置的终结点。 替代方法 字符串
connectionStringReference 包含 Azure 应用程序配置连接字符串的 Kubernetes 机密的名称。 替代方法 string
replicaDiscoveryEnabled 用于确定是否自动发现 Azure 应用程序配置的副本并将其用于故障转移的设置。 如果该属性不存在,则使用默认值 true false 布尔
loadBalancingEnabled 使工作负荷能够在所有可用副本之间分发请求以应用程序配置的设置。 如果该属性不存在,则使用默认值 false false 布尔
目标 Kubernetes 中检索到的键值的目标。 object
auth 用于访问 Azure 应用程序配置的身份验证方法。 false object
配置 Azure 应用配置中用于查询和处理键值的设置。 false object
secret Azure 应用配置中用于 Key Vault 引用的设置。 conditional object
featureFlag Azure 应用程序配置中功能标志的设置。 false object

spec.target 属性具有以下子属性。

名称 说明 必需 类型
configMapName 要创建的 ConfigMap 的名称。 string
configMapData 该设置指定如何在生成的 ConfigMap 中填充检索到的数据。 false object

如果未设置 spec.target.configMapData 属性,则生成的 ConfigMap 将使用从 Azure 应用程序配置检索到的键值列表进行填充,这样 ConfigMap 便可以用作环境变量。 如果要将 ConfigMap 用作装载的文件,请更新此属性。 此属性具有以下子属性。

名称 说明 必需 类型
type 指示如何在生成的 ConfigMap 中构造检索到的数据的设置。 允许的值包括 defaultjsonyamlproperties 可选 string
key type 设置为 jsonyamlproperties 时检索到的数据的键名称。 如果将 ConfigMap 设置为作为装载的文件使用,请将其设置为文件名。 conditional string
separator 分隔符,用于在类型设置为 jsonyaml 时以分层格式输出 ConfigMap 数据。 默认情况下分隔符为空,生成的 ConfigMap 包含原始形式的键值。 仅当应用程序中使用的配置文件加载器无法在不将键-值转换为分层格式的情况下加载它们时,才配置此设置。 可选 string

如果你的应用程序配置存储的连接字符串是通过设置 spec.connectionStringReference 属性提供的,则不需要 spec.auth 属性。 否则,其中一个标识、服务主体、工作负载标识或托管标识将用于身份验证。 spec.auth 具有以下子属性。 只应指定其中一个。 如果未设置它们,则将使用虚拟机规模集的系统分配的托管标识。

名称 说明 必需 类型
servicePrincipalReference 包含服务主体凭据的 Kubernetes 机密的名称。 该机密必须与 Kubernetes 提供程序位于同一命名空间中。 false string
workloadIdentity 使用工作负载标识的设置。 false object
managedIdentityClientId 虚拟机规模集的用户分配的托管标识的客户端 ID。 false string

spec.auth.workloadIdentity 属性具有以下子属性。

名称 说明 必需 类型
serviceAccountName 与工作负荷标识关联的服务帐户的名称。 string

spec.configuration 具有以下子属性。

名称 说明 必需 类型
选择器 键值筛选的选择器列表。 false 对象数组
trimKeyPrefixes 要修整的键前缀列表。 false 字符串数组
刷新 关于刷新 Azure 应用程序配置中的键值的设置。 如果该属性不存在,则不会刷新 Azure 应用程序配置中的键值。 false object

如果未设置 spec.configuration.selectors 属性,则下载不带标签的所有键值。 它包含具有以下子属性的选择器对象的数组。 请注意,最后一个选择器的键值优先并替代先前选择器中的任何重叠键。

名称 说明 必需 类型
keyFilter 用于查询键值的键筛选器。 不应同时设置此属性和 snapshotName 属性。 替代方法 string
labelFilter 用于查询键值的标签筛选器。 不应同时设置此属性和 snapshotName 属性。 false string
snapshotName 从中加载了键值的快照的名称。 此属性不应与其他属性结合使用。 替代方法 string

spec.configuration.refresh 属性具有以下子属性。

名称 说明 必需 类型
enabled 用于确定是否自动刷新 Azure 应用程序配置中的键值的设置。 如果该属性不存在,则使用默认值 false false bool
监视 为更改检测监视的键值,又名 sentinel 键。 仅当至少更改了一个受监视的键值时,才会刷新 Azure 应用程序配置中的键值。 如果此属性不存在,将监视所有选定的键值进行刷新。 false object
interval 从 Azure 应用程序配置刷新键值的间隔。 该值必须大于或等于 1 秒。 如果该属性不存在,则使用默认值 30 秒。 false 持续时间字符串

spec.configuration.refresh.monitoring.keyValues 为对象的数组,包含以下子属性。

名称 说明 必需 类型
key 键值键。 字符串
label 键值的标签。 false string

spec.secret 属性具有以下子属性。 如果要下载任何密钥保管库引用,则需要它。 若要详细了解对 Kubernetes 内置机密类型的支持,请参阅机密类型

名称 说明 必需 类型
target Kubernetes 中检索到的机密的目标。 object
auth 访问密钥保管库的身份验证方法。 false object
refresh 用于从密钥保管库刷新数据的设置。 如果该属性不存在,除非重新加载相应的 Key Vault 引用,否则不会刷新 Key Vault 中的数据。 false object

spec.secret.target 属性具有以下子属性。

名称 说明 必需 类型
secretName 要创建的 Kubernetes 机密的名称。 字符串

如果未设置 spec.secret.auth 属性,则会使用系统分配的托管标识。 它具有以下子属性。

名称 说明 必需 类型
servicePrincipalReference Kubernetes 机密的名称,机密包含用于对未指定单个身份验证方法的 Key Vault 进行身份验证的服务主体的凭据。 false string
workloadIdentity 用于向未指定单个身份验证方法的 Key Vault 进行身份验证的工作负载标识的设置。 它具有与 spec.auth.workloadIdentity 相同的子属性。 false object
managedIdentityClientId 用于向未指定单个身份验证方法的 Key Vault 进行身份验证的虚拟机规模集的用户分配的托管标识的客户端 ID。 false string
keyVaults 单个 Key Vault 的身份验证方法。 false 对象数组

可以使用以下属性指定每个 Key Vault 的身份验证方法。 必须提供 managedIdentityClientIdservicePrincipalReferenceworkloadIdentity 中的一个。

名称 说明 必需 类型
uri Key Vault 的 URI。 string
servicePrincipalReference Kubernetes 机密的名称,机密包含用于对 Key Vault 进行身份验证的服务主体的凭据。 false string
workloadIdentity 用于向 Key Vault 进行身份验证的工作负载标识的设置。 它具有与 spec.auth.workloadIdentity 相同的子属性。 false object
managedIdentityClientId 用于向 Key Vault 进行身份验证的虚拟机规模集的用户分配的托管标识的客户端 ID。 false string

spec.secret.refresh 属性具有以下子属性。

名称 说明 必需 类型
enabled 确定是否自动刷新 Key Vault 中的数据的设置。 如果该属性不存在,则使用默认值 false false bool
interval 从 Key Vault 刷新数据的间隔。 该值必须大于或等于 1 分钟。 密钥保管库刷新独立于通过 spec.configuration.refresh 配置的应用程序配置刷新。 持续时间字符串

spec.featureFlag 属性具有以下子属性。 如果需要下载任何功能标志,则需要该属性。

名称 说明 必需 类型
选择器 用于筛选功能标志的选择器列表。 false 对象数组
刷新 关于刷新 Azure 应用程序配置中的功能标志的设置。 如果该属性不存在,则不会刷新 Azure 应用程序配置中的功能标志。 false object

如果未设置 spec.featureFlag.selectors 属性,则不会下载功能标志。 它包含具有以下子属性的选择器对象的数组。 请注意,最后一个选择器的功能标志优先并替代先前选择器中的任何重叠键。

名称 说明 必需 类型
keyFilter 用于查询功能标志的关键筛选器。 不应同时设置此属性和 snapshotName 属性。 替代方法 string
labelFilter 用于查询功能标志的标签筛选器。 不应同时设置此属性和 snapshotName 属性。 false string
snapshotName 从中加载了功能标志的快照的名称。 此属性不应与其他属性结合使用。 替代方法 string

spec.featureFlag.refresh 属性具有以下子属性。

名称 说明 必需 类型
enabled 用于确定是否自动刷新 Azure 应用程序配置中的功能标志的设置。 如果该属性不存在,则使用默认值 false false bool
interval 从 Azure 应用程序配置刷新功能标志的间隔。 该值必须大于或等于 1 秒。 如果该属性不存在,则使用默认值 30 秒。 false 持续时间字符串

安装

使用以下 helm install 命令安装 Azure 应用程序配置 Kubernetes 提供程序。 有关参数及其默认值的完整列表,请参阅 helm-values.yaml。 可以通过将 --set 标志传递给命令来替代默认值。

helm install azureappconfiguration.kubernetesprovider \
    oci://mcr.microsoft.com/azure-app-configuration/helmchart/kubernetes-provider \
    --namespace azappconfig-system \
    --create-namespace

自动缩放

默认禁用自动缩放。 但是,如果使用多个 AzureAppConfigurationProvider 资源来生成多个 ConfigMap/机密,则可以通过将 autoscaling.enabled 设置为 true来启用水平 Pod 自动缩放。

helm install azureappconfiguration.kubernetesprovider \
    oci://mcr.microsoft.com/azure-app-configuration/helmchart/kubernetes-provider \
    --namespace azappconfig-system \
    --create-namespace
    --set autoscaling.enabled=true

数据收集

该软件可能会收集有关你及其使用的信息,并将其发送到Microsoft。 Microsoft 可能使用此信息提供服务和改进我们的产品和服务。 可以通过在安装 Azure 应用程序配置 Kubernetes 提供程序时设置requestTracing.enabled=false来关闭遥测。 软件中还有一些功能,这些功能可能使你和Microsoft从应用程序的用户收集数据。 如果使用这些功能,则必须遵守适用法律,包括向应用程序用户提供适当的通知以及Microsoft隐私声明的副本。 我们的隐私声明载于 https://go.microsoft.com/fwlink/?LinkID=824704。 可以在帮助文档和隐私声明中了解有关数据收集和使用的详细信息。 一旦使用该软件,即表示您同意这些做法。

示例

身份验证

使用虚拟机规模集的系统分配的托管标识

  1. 在 Azure Kubernetes 服务 (AKS) 群集使用的虚拟机规模集中启用系统分配的托管标识

  2. 在 Azure 应用程序配置中授予系统分配的托管标识应用程序配置数据读取者角色

  3. 将以下示例 AzureAppConfigurationProvider 资源部署到 AKS 群集。

    apiVersion: azconfig.io/v1
    kind: AzureAppConfigurationProvider
    metadata:
      name: appconfigurationprovider-sample
    spec:
      endpoint: <your-app-configuration-store-endpoint>
      target:
        configMapName: configmap-created-by-appconfig-provider
    

使用虚拟机规模集的用户分配的托管标识

  1. 创建用户分配的托管标识,并在创建后记下其客户端 ID。

  2. 将用户分配的托管标识分配给 Azure Kubernetes 服务 (AKS) 群集使用的虚拟机规模集

  3. 在 Azure 应用程序配置中授予用户分配的托管标识应用程序配置数据读取者角色

  4. spec.auth.managedIdentityClientId 属性设置为以下示例 AzureAppConfigurationProvider 资源中用户分配的托管标识的客户端 ID,并将其部署到 AKS 群集。

    apiVersion: azconfig.io/v1
    kind: AzureAppConfigurationProvider
    metadata:
      name: appconfigurationprovider-sample
    spec:
      endpoint: <your-app-configuration-store-endpoint>
      target:
        configMapName: configmap-created-by-appconfig-provider
      auth:
        managedIdentityClientId: <your-managed-identity-client-id>
    

使用服务主体

  1. 创建服务主体

  2. 在 Azure 应用程序配置中授予服务主体应用程序配置数据读取者角色

  3. 在与 AzureAppConfigurationProvider 资源相同的命名空间中创建 Kubernetes 机密,并将服务主体的 azure_client_idazure_client_secretazure_tenant_id 添加到机密。

  4. spec.auth.servicePrincipalReference 属性设置为以下示例 AzureAppConfigurationProvider 资源中机密的名称,并将其部署到 Kubernetes 群集。

    apiVersion: azconfig.io/v1
    kind: AzureAppConfigurationProvider
    metadata:
      name: appconfigurationprovider-sample
    spec:
      endpoint: <your-app-configuration-store-endpoint>
      target:
        configMapName: configmap-created-by-appconfig-provider
      auth:
        servicePrincipalReference: <your-service-principal-secret-name>
    

使用工作负载标识

  1. 在 Azure Kubernetes 服务 (AKS) 群集上启用工作负载标识

  2. 获取 AKS 群集的 OIDC 颁发者 URL

  3. 创建用户分配的托管标识并记下其客户端 ID、租户 ID、名称和资源组。

  4. 在 Azure 应用程序配置中授予用户分配的托管标识应用程序配置数据读取者角色

  5. 通过将 YAML 文件(例如 serviceAccount.yaml)以及以下内容添加到包含 AKS 部署文件的目录,创建服务帐户。 将所有部署更改应用于 AKS 群集(例如,使用 kubectl apply)时,将创建服务帐户。 将 <your-managed-identity-client-id> 替换为刚创建的用户分配的托管标识的客户端 ID,并将 <your-managed-identity-tenant-id> 替换为其租户 ID。 将 <your-service-account-name> 替换为首选名称。

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: <your-service-account-name>
      annotations:
        azure.workload.identity/client-id: <your-managed-identity-client-id>
        azure.workload.identity/tenant-id: <your-managed-identity-tenant-id>
    
  6. 使用 Azure CLI 为用户分配的托管标识创建联合标识凭据。 将 <user-assigned-identity-name> 替换为新创建的用户分配的托管标识的名称,并将 <resource-group> 替换为其资源组。 将 <aks-oidc-issuer> 替换为 AKS 群集的 OIDC 颁发者 URL。 将 <your-service-account-name> 替换为创建的服务帐户的名称。 将 <federated-identity-credential-name> 替换为联合标识凭据的首选名称。

    az identity federated-credential create --name "<federated-identity-credential-name>" --identity-name "<user-assigned-identity-name>" --resource-group "<resource-group>" --issuer "<aks-oidc-issuer>" --subject system:serviceaccount:default:<your-service-account-name> --audience api://AzureADTokenExchange
    

    请注意,联合标识凭据的主体应遵循以下格式:system:serviceaccount:<service-account-namespace>:<service-account-name>

  7. 在以下示例 AzureAppConfigurationProvider 资源中,将 spec.auth.workloadIdentity.serviceAccountName 属性设置为服务帐户的名称。 确保 AzureAppConfigurationProvider 资源和服务帐户位于同一命名空间中。

    apiVersion: azconfig.io/v1
    kind: AzureAppConfigurationProvider
    metadata:
      name: appconfigurationprovider-sample
    spec:
      endpoint: <your-app-configuration-store-endpoint>
      target:
        configMapName: configmap-created-by-appconfig-provider
      auth:
        workloadIdentity:
          serviceAccountName: <your-service-account-name>
    

使用连接字符串

  1. 在与 AzureAppConfigurationProvider 资源相同的命名空间中创建 Kubernetes 机密,并在机密中添加具有密钥azure_app_configuration_connection_string 的 Azure 应用程序配置连接字符串。

  2. spec.connectionStringReference 属性设置为以下示例 AzureAppConfigurationProvider 资源中机密的名称,并将其部署到 Kubernetes 群集。

    apiVersion: azconfig.io/v1
    kind: AzureAppConfigurationProvider
    metadata:
      name: appconfigurationprovider-sample
    spec:
      connectionStringReference: <your-connection-string-secret-name>
      target:
        configMapName: configmap-created-by-appconfig-provider
    

键值选择

使用 selectors 属性筛选要从 Azure 应用程序配置下载的键值。

以下示例下载了所有不带标签的键值。

apiVersion: azconfig.io/v1
kind: AzureAppConfigurationProvider
metadata:
  name: appconfigurationprovider-sample
spec:
  endpoint: <your-app-configuration-store-endpoint>
  target:
    configMapName: configmap-created-by-appconfig-provider

在以下示例中,两个选择器用于检索两组键值,每个键值都有唯一的标签。 请务必注意,最后一个选择器的值优先,并替代先前选择器中的任何重叠键。

apiVersion: azconfig.io/v1
kind: AzureAppConfigurationProvider
metadata:
  name: appconfigurationprovider-sample
spec:
  endpoint: <your-app-configuration-store-endpoint>
  target:
    configMapName: configmap-created-by-appconfig-provider
  configuration:
    selectors:
      - keyFilter: app1*
        labelFilter: common
      - keyFilter: app1*
        labelFilter: development

快照可以单独使用,也可以与其他键值选择器一起使用。 在以下示例中,你将从快照加载通用配置的键值,然后使用这些键值替代其中一些键值以进行开发。

apiVersion: azconfig.io/v1
kind: AzureAppConfigurationProvider
metadata:
  name: appconfigurationprovider-sample
spec:
  endpoint: <your-app-configuration-store-endpoint>
  target:
    configMapName: configmap-created-by-appconfig-provider
  configuration:
    selectors:
      - snapshotName: app1_common_configuration
      - keyFilter: app1*
        labelFilter: development

键前缀修整

以下示例使用 trimKeyPrefixes 属性修整键名中的两个前缀,然后将它们添加到生成的 ConfigMap。

apiVersion: azconfig.io/v1
kind: AzureAppConfigurationProvider
metadata:
  name: appconfigurationprovider-sample
spec:
  endpoint: <your-app-configuration-store-endpoint>
  target:
    configMapName: configmap-created-by-appconfig-provider
  configuration:
    trimKeyPrefixes: [prefix1, prefix2]

配置刷新

对 Azure 应用程序配置中的数据进行更改时,你可能希望在 Kubernetes 群集中自动刷新这些更改。 更新多个键值很常见,但你不希望群集在更新中途选取更改。 若要保持配置一致性,可以使用键值来指示更新完成。 此键值称为 sentinel 键。 Kubernetes 提供程序可以监视此键值,只有在 sentinel 密钥中检测到更改后,才会使用更新的数据重新生成 ConfigMap 和机密。

在以下示例中,每分钟轮询一个名为 的 app1_sentinel 键值,并在 sentinel 键中检测到更改时刷新配置。

apiVersion: azconfig.io/v1
kind: AzureAppConfigurationProvider
metadata:
  name: appconfigurationprovider-sample
spec:
  endpoint: <your-app-configuration-store-endpoint>
  target:
    configMapName: configmap-created-by-appconfig-provider
  configuration:
    selectors:
      - keyFilter: app1*
        labelFilter: common
    refresh:
      enabled: true
      interval: 1m
      monitoring:
        keyValues:
          - key: app1_sentinel
            label: common

Key Vault 引用

身份验证

在以下示例中,一个密钥保管库使用服务主体进行身份验证,而所有其他密钥保管库均使用用户分配的托管标识进行身份验证。

apiVersion: azconfig.io/v1
kind: AzureAppConfigurationProvider
metadata:
  name: appconfigurationprovider-sample
spec:
  endpoint: <your-app-configuration-store-endpoint>
  target:
    configMapName: configmap-created-by-appconfig-provider
  configuration:
    selectors:
      - keyFilter: app1*
  secret:
    target:
      secretName: secret-created-by-appconfig-provider
    auth:
      managedIdentityClientId: <your-user-assigned-managed-identity-client-id>
      keyVaults:
        - uri: <your-key-vault-uri>
          servicePrincipalReference: <name-of-secret-containing-service-principal-credentials>

机密的类型

目前支持两种 Kubernetes 内置机密类型:不透明和 TLS。 默认情况下,从密钥保管库引用解析的机密保存为不透明机密类型。 如果你有对证书的密钥保管库引用,并希望将其保存为 TLS 机密类型,你可以将具有以下名称和值的标记添加到 Azure 应用程序配置中的密钥保管库引用。 这样会生成一个类型为 kubernetes.io/tls 的机密,其名称与密钥保管库引用的密钥相同。

名称
.kubernetes.secret.type kubernetes.io/tls

以下示例演示了如何使用不同类型的生成的机密填充数据。

假设应用程序配置存储具有以下密钥库引用:

key value 标记
app1-secret1 <密钥库参考 1> {}
app1-secret2 <密钥库参考 2> {}
app1-certificate <密钥库参考 3> {".kubernetes.secret.type": "kubernetes.io/tls"}

下面的示例生成不透明和 TLS 类型的机密。

apiVersion: azconfig.io/v1
kind: AzureAppConfigurationProvider
metadata:
  name: appconfigurationprovider-sample
spec:
  endpoint: <your-app-configuration-store-endpoint>
  target:
    configMapName: configmap-created-by-appconfig-provider
  configuration:
    selectors:
      - keyFilter: app1*
  secret:
    target:
      secretName: secret-created-by-appconfig-provider
    auth:
      managedIdentityClientId: <your-user-assigned-managed-identity-client-id>

生成的机密填充了以下数据:

name: secret-created-by-appconfig-provider
type: Opaque
data:
  app1-secret1: <secret value retrieved from Key Vault>
  app1-secret2: <secret value retrieved from Key Vault>
name: app1-certificate
type: kubernetes.io/tls
data:
  tls.crt: |
    <certificate data retrieved from Key Vault>
  tls.key: |
    <certificate key retrieved from Key Vault>

从密钥保管库刷新机密

从密钥保管库刷新机密通常需要从 Azure 应用程序配置重新加载相应的密钥保管库引用。 但是,使用 spec.secret.refresh 属性可以从密钥保管库单独刷新机密。 这对于确保工作负载在机密轮换期间从密钥保管库自动选取任何更新的机密特别有用。 请注意,若要加载最新版本的机密,密钥保管库引用不得为版本控制机密。

以下示例每小时刷新密钥保管库的所有非版本控制机密。

apiVersion: azconfig.io/v1
kind: AzureAppConfigurationProvider
metadata:
  name: appconfigurationprovider-sample
spec:
  endpoint: <your-app-configuration-store-endpoint>
  target:
    configMapName: configmap-created-by-appconfig-provider
  configuration:
    selectors:
      - keyFilter: app1*
        labelFilter: common
  secret:
    target:
      secretName: secret-created-by-appconfig-provider
    auth:
      managedIdentityClientId: <your-user-assigned-managed-identity-client-id>
    refresh:
      enabled: true
      interval: 1h

功能标志

在以下示例中,键以 app1 开头的功能标志和等效于 common 的标签每 10 分钟下载并刷新一次。 请注意,若要在生成的 ConfigMap 中填充功能标志,属性“configMapData.type”必须是“json”或“yaml”。

apiVersion: azconfig.io/v1
kind: AzureAppConfigurationProvider
metadata:
  name: appconfigurationprovider-sample
spec:
  endpoint: <your-app-configuration-store-endpoint>
  target:
    configMapName: configmap-created-by-appconfig-provider
    configMapData:
      type: json
      key: appSettings.json
  featureFlag:
    selectors:
      - keyFilter: app1*
        labelFilter: common
    refresh:
      enabled: true
      interval: 10m

ConfigMap 消耗

Kubernetes 中运行的应用程序通常使用 ConfigMap 作为环境变量或配置文件。 如果 configMapData.type 属性不存在或设置为默认值,则 ConfigMap 将填充从 Azure 应用程序配置检索到的项化数据列表,它可以轻松用作环境变量。 如果 configMapData.type 属性设置为 json、yaml 或属性,则从 Azure 应用程序配置中检索到的数据将分组到一个项中,其中包含由生成的 ConfigMap 中的 configMapData.key 属性指定的键名称,它可以用作装载的文件。

以下示例演示如何使用 configMapData.type 属性的不同设置在生成的 ConfigMap 中填充数据。

假设应用程序配置存储具有以下键值:

key value
key1 value1
key2 value2
key3 value3

configMapData.type 属性不存在或设置为 default

apiVersion: azconfig.io/v1
kind: AzureAppConfigurationProvider
metadata:
  name: appconfigurationprovider-sample
spec:
  endpoint: <your-app-configuration-store-endpoint>
  target:
    configMapName: configmap-created-by-appconfig-provider

生成的 ConfigMap 将用以下数据填充:

data:
  key1: value1
  key2: value2
  key3: value3