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

Helm 包最佳做法

Helm 是 Kubernetes 的包管理器,可帮助简化应用程序生命周期管理。 Helm 包称为 chart,由 YAML 配置和模板文件组成。 执行 Helm 操作后,图表将呈现到 Kubernetes 清单文件中,以触发相应的应用程序生命周期操作。 为了最有效地与 Azure 操作员服务管理器集成,请在开发 Helm 图表时遵循这些建议的最佳做法。

registryPath 和 imagePullSecrets 的注意事项

每个 Helm chart 通常都需要 registryPathimagePullSecrets 参数。 最常见的情况是在 values.yaml 文件中公开这些参数。 起初,Azure 运营商服务管理器依赖于发布者以严格的方式管理这些值(旧方法),以在部署期间将其替换为正确的 Azure 值。 但是,并非所有发布者都能够轻松遵守相关规范来对这些值进行严格的管理。 某些 chart 将 registryPath 和/或 imagePullSecrets 隐藏在条件或其他值限制后面,而这些限制并不是总能得到满足。 某些 chart 将 registryPath 和/或 imagePullSecrets 声明为数组,而不是预期的命名字符串。

为了减少对发布者的合规性要求,Azure 运营商服务管理器引入了两种改进的方法:injectArtifactStoreDetail 和群集注册表。 这些较新的方法不依赖于 Helm 包中出现的 registryPathimagePullSecrets。 在这种情况下,这些方法使用 Webhook 将适当的 Azure 值直接注入 Pod 操作。

registryPath 和 imagePullSecrets 的方法摘要

目前支持所有三种方法,如本文所述。 为网络功能 (NF) 和用例选择最佳选项。

旧方法:

  • 要求在 Helm 值和部署模板中参数化 registryPathimagePullSecrets 以进行替换。
  • 在 Azure 容器注册表中托管映像。

InjectArtifactStoreDetail:

  • 使用 Webhook 将 registryPathimagePullSecrets 直接注入 Pod 操作中,对 Helm 的依赖性最小。
  • 在 Azure 容器注册表中托管映像。

群集注册表:

  • 使用 Webhook 将 registryPathimagePullSecrets 直接注入 Pod 操作中,不依赖于 Helm。
  • 在本地网络功能运营商 (NFO) 扩展中托管映像。

在所有三种情况下,Azure 运营商服务管理器都会用 Azure 值替换模板中公开的任何值。 唯一的区别是替换方法。

registryPath 和 imagePullSecrets 的旧要求

Azure 运营商服务管理器使用 Azure 网络功能管理器服务来部署容器化网络功能 (CNF)。 使用旧方法时,Azure 网络功能管理器会在部署网络功能期间将 Azure 运营商服务管理器容器的 registryPathimagePullSecrets 值替换到 Helm 操作中。

旧方法的示例

以下 Helm 部署模板以示例方式演示了应如何公开 registryPathimagePullSecrets

apiVersion: apps/v1 
kind: Deployment 
metadata: 
  name: nginx-deployment 
  labels: 
    app: nginx 
spec: 
  replicas: 3 
  selector: 
    matchLabels: 
      app: nginx 
  template: 
    metadata: 
      labels: 
        app: nginx 
    spec: 
      {{- if .Values.global.imagePullSecrets }} 
      imagePullSecrets: {{ toYaml .Values.global.imagePullSecrets | nindent 8 }} 
      {{- end }} 
      containers: 
      - name: contosoapp 
        image:{{ .Values.global.registryPath }}/contosoapp:1.14.2 
        ports: 
        - containerPort: 80 

以下 values.yaml 模板以示例方式演示了可如何提供 registryPathimagePullSecrets 值:

global: 
   imagePullSecrets: [] 
   registryPath: "" 

以下 values.schema.json 文件以示例方式演示了可如何定义 registryPathimagePullSecrets 值:

{ 
  "$schema": "http://json-schema.org/draft-07/schema#", 
  "title": "StarterSchema", 
  "type": "object", 
  "required": ["global"], 
  "properties": { 
      "global" : {
          "type": "object",
          "properties": {
              "registryPath": {"type": "string"}, 
              "imagePullSecrets": {"type": "string"}, 
          }
          "required": [ "registryPath", "imagePullSecrets" ], 
      } 
   } 
} 

以下网络功能定义版本 (NFDV) 请求有效负载以示例方式演示了可如何在部署时提供 registryPathimagePullSecrets 值:

"registryValuesPaths": [ "global.registryPath" ], 
"imagePullSecretsValuesPaths": [ "global.imagePullSecrets" ], 

在前面的示例中:

  • 设置 registryPath 值时不带任何前缀(例如 https://oci://)。 必要时请在 Helm 包中定义前缀。
  • imagePullSecretsregistryPath 必须在 NFDV 载入期间提供。

其他注意事项

使用旧方法时,请考虑以下建议。

避免引用外部注册表

引用外部注册表可能会导致验证问题。 例如,如果 deployment.yaml 使用硬编码的注册表路径或外部注册表引用,则无法通过验证。

执行手动验证

查看映像和容器规范,确保映像具有前缀 registryPathimagePullSecrets 中填充了 secretName

 helm template --set "global.imagePullSecrets[0].name=<secretName>" --set "global.registry.url=<registryPath>" <release-name> <chart-name> --dry-run

以下是另一示例:

 helm install --set "global.imagePullSecrets[0].name=<secretName>" --set "global.registry.url=<registryPath>" <release-name> <chart-name> --dry-run
 kubectl create secret <secretName> regcred --docker-server=<registryPath> --dockerusername=<regusername> --docker-password=<regpassword>

使用静态映像存储库和标记

每个 Helm chart 都应包含静态映像存储库和标记。 请通过以下方法之一设置静态值:

  • image 行中
  • values.yaml 中,不在 NFDV 中公开这些值

NFDV 应映射到一组静态 Helm chart 和映像。 仅通过发布新的 NFDV 来更新 chart 和映像,如以下示例所示:

 image: "{{ .Values.global.registryPath }}/contosoapp:1.14.2"
 image: "{{ .Values.global.registryPath }}/{{ .Values.image.repository }}:{{ .Values.image.tag}}"
 
YAML values.yaml
image:
  repository: contosoapp
  tag: 1.14.2
 image: http://myUrl/{{ .Values.image.repository }}:{{ .Values.image.tag}}

registryPath 和 imagePullSecrets 的 injectArtifactStoreDetails 要求

在某些情况下,第三方 Helm 图表可能不符合 Azure 运营商服务管理器的 registryPath 要求。 在这些情况下,可以使用 injectArtifactStoreDetails 来避免对 Helm 包进行合规性更改。

启用 injectArtifactStoreDetails 后,请使用 Webhook 方法在 Pod 操作期间动态注入适当的 registryPathimagePullSecrets。 此方法替代 Helm 包中配置的值。 仍然必须在引用 registryPathimagePullSecrets 的地方(通常在 globalvalues.yaml 节中)使用合法的虚拟值。

以下 values.yaml 示例展示了如何提供 registryPathimagePullSecrets 值,以实现与 injectArtifactStoreDetails 方法的兼容:

global: 
   registryPath: "azure.io"
   imagePullSecrets: ["abc123"] 

注意

如果在基础 Helm 包中将 registryPath 留空,则在映像下载过程中进行的站点网络服务 (SNS) 部署会失败。

使用 injectArtifactStoreDetails 方法

若要启用 injectArtifactStoreDetails,请将 NF 资源的 installOptions 节中的 roleOverrides 参数设置为 true,如以下示例所示:

resource networkFunction 'Microsoft.HybridNetwork/networkFunctions@2023-09-01' = {
  name: nfName
  location: location
  properties: {
    nfviType: 'AzureArcKubernetes'
    networkFunctionDefinitionVersionResourceReference: {
      id: nfdvId
      idType: 'Open'
    }
    allowSoftwareUpdate: true
    nfviId: nfviId
    deploymentValues: deploymentValues
    configurationType: 'Open'
    roleOverrideValues: [
      // Use inject artifact store details feature on test app 1
      '{"name":"testapp1", "deployParametersMappingRuleProfile":{"helmMappingRuleProfile":{"options":{"installOptions":{"atomic":"false","wait":"false","timeout":"60","injectArtifactStoreDetails":"true"},"upgradeOptions": {"atomic": "false", "wait": "true", "timeout": "100", "injectArtifactStoreDetails": "true"}}}}}'
    ]
  }
}

注意

Helm chart 包仍然必须公开格式正确的 registryPathimagePullSecrets 值。

registryPath 和 imagePullSecrets 的群集注册表要求

使用群集注册表时,映像将从 Azure 容器注册表复制到关系 Kubernetes 群集上的本地 Docker 存储库。 请使用 Webhook 方法在 Pod 操作期间动态注入适当的 registryPathimagePullSecrets 值。 此方法替代 Helm 包中配置的值。 仍然必须在引用 registryPathimagePullSecrets 的地方(通常在 globalvalues.yaml 节中)使用合法的虚拟值。

以下 values.yaml 示例展示了如何提供 registryPathimagePullSecrets 值,以实现与群集注册表方法的兼容:

global: 
   registryPath: "azure.io"
   imagePullSecrets: ["abc123"] 

注意

如果在基础 Helm 包中将 registryPath 留空,则在映像下载过程中进行的 SNS 部署会失败。

若要详细了解如何使用群集注册表,请参阅概念文档

关于不可变性限制的建议

不可变性限制可防止更改文件或目录。 例如,无法更改或重命名不可变文件。 应避免使用可变标记,例如 latestdevstable。 例如,如果使用 deployment.yamllatest 使用 .Values.image.tag,部署会失败。

 image: "{{ .Values.global.registryPath }}/{{ .Values.image.repository }}:{{ .Values.image.tag}}"

有关 CRD 声明和使用情况拆分的建议

建议将客户资源定义 (CRD) 的声明和使用情况拆分为单独的 Helm chart,以支持更新。 有关详细信息,请参阅有关如何分隔 chart 的 Helm 文档

有关映像版本标记的建议

为了确保进行一致且可预测的部署,建议对所有容器映像执行以下操作:

  • 避免在生产环境中使用 :latest
    • 使用 latest 可能会导致意外行为,因为 latest 背后的实际映像可能会发生变化,不会另行通知。
    • 在群集注册表设置中,如果标记值更改但标记名称保持不变,则群集注册表不会重新下载更新的映像。
    • 这可能会导致运行过时的或不一致的映像。
  • 相反,请始终使用不可变标记,例如 :1.4.2
  • 确保每个内部版本都生成唯一的标记,不要覆盖现有标记。

这些做法有助于防止部署问题并提高可跟踪性、回滚安全性和安全合规性。

有关 nfApplication 顺序排序的建议

默认情况下,CNF 应用程序会根据它们在 NFDV 中显示的顺序进行安装或更新。 对于删除操作,CNF 应用程序将按指定的相反顺序删除。 如果需要定义与默认顺序不同的 CNF 应用程序特定顺序,请使用 dependsOnProfile 来定义安装、更新和删除操作的唯一序列。

如何使用 dependsOnProfile

可以在 NFDV 中使用 dependsOnProfile 来控制 CNF 应用程序的 Helm 执行序列。 在下面的示例中:

  • 在安装操作期间,CNF 应用程序按以下顺序进行部署:dummyApplication1dummyApplication2dummyApplication
  • 在更新操作期间,CNF 应用程序按以下顺序进行更新:dummyApplication2dummyApplication1dummyApplication
  • 在删除操作期间,CNF 应用程序按以下顺序进行删除:dummyApplication2dummyApplication1dummyApplication
{
    "location": "eastus",
    "properties": {
        "networkFunctionTemplate": {
            "networkFunctionApplications": [
                {
                  "dependsOnProfile": {
                        "installDependsOn": [
                            "dummyApplication1",
                            "dummyApplication2"
                        ],
                        "uninstallDependsOn": [
                            "dummyApplication1"
                        ],
                        "updateDependsOn": [
                            "dummyApplication1"
                        ]
                    },
                    "name": "dummyApplication"
                },
                {
                  "dependsOnProfile": {
                        "installDependsOn": [
                        ],
                        "uninstallDependsOn": [
                            "dummyApplication2"
                        ],
                        "updateDependsOn": [
                            "dummyApplication2"
                        ]
                    },
                    "name": "dummyApplication1"
                },
                {
                    "dependsOnProfile": null,
                    "name": "dummyApplication2"
                }
            ],
            "nfviType": "AzureArcKubernetes"
        },
        "networkFunctionType": "ContainerizedNetworkFunction"
    }
}

dependsOnProfile 的常见错误

目前,如果 NFDV 中提供的 dependsOnProfile 代码无效,则 NF 操作将失败,并出现验证错误。 验证错误消息会显示在操作状态资源中,如以下示例所示:

 {
  "id": "/providers/Microsoft.HybridNetwork/locations/EASTUS2EUAP/operationStatuses/ca051ddf-c8bc-4cb2-945c-a292bf7b654b*C9B39996CFCD97AB3A121AE136ED47F67BB13946C573EF90628C47628BC5EF5F",
  "name": "ca051ddf-c8bc-4cb2-945c-a292bf7b654b*C9B39996CFCD97AB3A121AE136ED47F67BB13946C573EF90628C47628BC5EF5F",
  "resourceId": "/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/xinrui-publisher/providers/Microsoft.HybridNetwork/networkfunctions/testnfDependsOn02",
  "status": "Failed",
  "startTime": "2023-07-17T20:48:01.4792943Z",
  "endTime": "2023-07-17T20:48:10.0191285Z",
  "error": {
    "code": "DependenciesValidationFailed",
    "message": "CyclicDependencies: Circular dependencies detected at hellotest."
  }
}