参考

Edit This Page

动态准入控制

admission 控制器文档 介绍如何使用标准的插件式 admission 控制器。然而, 由于以下原因插件 admission 控制器对于所有用例来说都不够灵活:

  • 他们需要编译到 kube-apiserver 里面。
  • 它们仅在 apiserver 启动时可配置。

*Admission Webhooks*(1.9 版中的 beta)解决了这些限制。 它允许 admission 控制器能被独立开发以及在运行时配置。

本页介绍如何使用 Admission Webhooks。

什么是 admission webhook?

Admission webhooks 是 HTTP 回调,它接收 admission 请求并对它们做一些事情。 您可以定义两种类型的 admission webhook, validating admission Webhookmutating admission webhook。 通过 validating admission Webhook,您可以拒绝请求以执行自定义的 admission 策略。 通过 mutating admission webhook,您可以更改请求以执行自定义的默认值。

尝试 admission webhook

admission webhook 本质上是集群控制平面的一部分。 您应该非常谨慎地编写和部署它们。 如果您打算编写/部署生产级 admission webhook,请阅读用户指南以获取相关说明。 在下文中,我们将介绍如何快速试验 admission webhook。

先决条件

  • 确保 Kubernetes 集群版本至少为 v1.9。

  • 确保启用 MutatingAdmissionWebhook 和 ValidatingAdmissionWebhook 控制器。 这里 是一组推荐的 admission 控制器,通常可以启用。

  • 确保启用了admissionregistration.k8s.io/v1beta1 API。

编写一个admission webhook 服务器

请参阅 Kubernetes e2e 测试中的 admission webhook 服务器实现。 webhook 处理由 apiservers 发送的 admissionReview 请求,并将其决定包含在 admissionResponse 中发回。

admissionReview 请求可以有不同的版本(例如,v1beta1 或未来版本中的 v1)。 webhook 可以使用 admissionReviewVersions 字段定义它们接受的版本。 apiserver 将尝试在其支持的列表中使用第一个版本。 如果 apiserver 不支持此列表中指定的任何版本,则此对象的验证将失败。 如果 webhook 配置依然如此,则对 webhook 的调用将失败并受到失败策略的控制。

示例 admission webhook 服务器置 ClientAuth 字段为 , 默认为 NoClientCert 。这意味着 webhook 服务器不会验证客户端的身份,认为其是 apiservers。 如果您需要双向 TLS 或其他方式来验证客户端,请参阅如何 验证-apiservers

部署 admission webhook 服务

e2e 测试中的 webhook 服务器部署在 Kubernetes 集群中,通过 deployment API。 该测试还创建了 service 作为 webhook 服务器的前端。 参见 code

您还可以在集群外部署 Webhook, 这需要相应地更新 webhook 客户端配置

即时配置 admission webhook

您可以动态配置哪些资源需要接受什么许可通过webhooks ValidatingWebhookConfiguration 要么 MutatingWebhookConfiguration

以下是一个示例ValidatingWebhookConfiguration,一个变异的 webhook 配置与此类似。有关每个配置字段的详细信息,请参见 webhook 配置部分。

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: "pod-policy.example.com"
webhooks:
- name: "pod-policy.example.com"
  rules:
  - apiGroups:   [""]
    apiVersions: ["v1"]
    operations:  ["CREATE"]
    resources:   ["pods"]
    scope:       "Namespaced"
  clientConfig:
    service:
      namespace: "example-namespace"
      name: "example-service"
    caBundle: "Ci0tLS0tQk...<base64-encoded PEM bundle containing the CA that signed the webhook's serving certificate>...tLS0K"
  admissionReviewVersions: ["v1", "v1beta1"]
  sideEffects: None
  timeoutSeconds: 5

# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
  name: "pod-policy.example.com"
webhooks:
- name: "pod-policy.example.com"
  rules:
  - apiGroups:   [""]
    apiVersions: ["v1"]
    operations:  ["CREATE"]
    resources:   ["pods"]
    scope:       "Namespaced"
  clientConfig:
    service:
      namespace: "example-namespace"
      name: "example-service"
    caBundle: "Ci0tLS0tQk...<base64-encoded PEM bundle containing the CA that signed the webhook's serving certificate>...tLS0K"
  admissionReviewVersions: ["v1beta1"]
  timeoutSeconds: 5

范围字段指定是仅集群范围的资源(Cluster)还是命名空间范围的资源资源(Namespaced)将与此规则匹配。*表示没有范围限制。

注意:

当使用clientConfig.service时,服务器证书必须对<svc_name>.<svc_namespace> .svc有效。

注意:

Webhook 呼叫的默认超时为 30 秒,但从 kubernetes 1.14 开始,可以设置超时,因此建议对 Webhooks 使用非常小的超时。 如果 webhook 呼叫超时,则根据 webhook 的请求处理请求失败政策。

当 apiserver 收到与rules匹配的请求时,apiserver 根据clientConfig配置定向给 webhook 发送admissionReview请求。

创建 webhook 配置后,系统将花费几秒钟来完成新配置的生效。

验证-apiservers

如果您的 webhooks 需要身份验证,您可以将 apiservers 配置为使用基本身份验证,不记名令牌或证书来对 webhook 进行身份验证。 完成配置有三个步骤。

  • 启动apiserver时,通过 --admission-control-config-file 参数指定许可控制配置文件的位置。

  • 在准入控制配置文件中,指定 MutatingAdmissionWebhook 控制器和 ValidatingAdmissionWebhook 控制器应该读取凭据的位置。 凭证存储在 kubeConfig 文件中(是​​的,与 kubectl 使用的模式相同),因此字段名称为kubeConfigFile。 以下是一个示例准入控制配置文件:

    apiVersion: apiserver.k8s.io/v1alpha1
    kind: AdmissionConfiguration
    plugins:
    - name: ValidatingAdmissionWebhook
    configuration:
    apiVersion: apiserver.config.k8s.io/v1alpha1
    kind: WebhookAdmission
    kubeConfigFile: "<path-to-kubeconfig-file>"
    - name: MutatingAdmissionWebhook
    configuration:
    apiVersion: apiserver.config.k8s.io/v1alpha1
    kind: WebhookAdmission
    kubeConfigFile: "<path-to-kubeconfig-file>"

admissionConfiguration的 shcema 定义在 这里. 有关每个配置字段的详细信息,请参见 webhook配置部分。

  • 在 kubeConfig 文件中,提供证书凭据:

    apiVersion: v1
    kind: Config
    users:
    # name should be set to the DNS name of the service or the host (including port) of the URL the webhook is configured to speak to.
    # If a non-443 port is used for services, it must be included in the name when configuring 1.16+ API servers.
    #
    # For a webhook configured to speak to a service on the default port (443), specify the DNS name of the service:
    # - name: webhook1.ns1.svc
    #   user: ...
    #
    # For a webhook configured to speak to a service on non-default port (e.g. 8443), specify the DNS name and port of the service in 1.16+:
    # - name: webhook1.ns1.svc:8443
    #   user: ...
    # and optionally create a second stanza using only the DNS name of the service for compatibility with 1.15 API servers:
    # - name: webhook1.ns1.svc
    #   user: ...
    #
    # For webhooks configured to speak to a URL, match the host (and port) specified in the webhook's URL. Examples:
    # A webhook with `url: https://www.example.com`:
    # - name: www.example.com 
    #   user: ...
    #
    # A webhook with `url: https://www.example.com:443`:
    # - name: www.example.com:443
    #   user: ...
    #
    # A webhook with `url: https://www.example.com:8443`:
    # - name: www.example.com:8443
    #   user: ...
    #
    - name: 'webhook1.ns1.svc'
    user:
    client-certificate-data: "<pem encoded certificate>"
    client-key-data: "<pem encoded key>"
    # The `name` supports using * to wildcard-match prefixing segments.
    - name: '*.webhook-company.org'
    user:
    password: "<password>"
    username: "<name>"
    # '*' is the default match.
    - name: '*'
    user:
    token: "<token>"

当然,您需要设置 webhook 服务器来处理这些身份验证。

请求

向 Webhooks 发送 POST 请求,头域带上Content-Type:application/json,与admission.k8s.io API groups 中的AdmissionReview API 对象一起使用 序列化为 JSON 作为主体。

Webhooks 可以指定他们接受的AdmissionReview对象的版本在配置中使用admissionReviewVersions字段:

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  admissionReviewVersions: ["v1", "v1beta1"]
  ...

创建时,admissionReviewVersions是必填字段admissionregistration.k8s.io/v1 Webhook配置。 需要 Webhooks 支持至少一项AdmissionReview当前和以前的 apiserver 可以解释的版本。

# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  admissionReviewVersions: ["v1beta1"]
  ...

如果未指定admissionReviewVersions,则创建时的默认值admissionregistration.k8s.io/v1beta1 Webhook 配置为v1beta1

apiserver 在其支持的admissionReviewVersions列表中发送第一个AdmissionReview版本。如果 apiserver 不支持列表中的任何版本,则不允许创建配置。 如果 apiserver 遇到先前创建的 Webhook 配置,并且不支持任何AdmissionReview apiserver 知道如何发送的版本,调用 Webhook 的尝试将失败,并受 失败策略 的约束。

此示例显示了AdmissionReview对象中包含的数据请求更新apps/v1 Deployment 的 scale 子资源:

{
  "apiVersion": "admission.k8s.io/v1",
  "kind": "AdmissionReview",
  "request": {
    # Random uid uniquely identifying this admission call
    "uid": "705ab4f5-6393-11e8-b7cc-42010a800002",

    # Fully-qualified group/version/kind of the incoming object
    "kind": {"group":"autoscaling","version":"v1","kind":"Scale"},
    # Fully-qualified group/version/kind of the resource being modified
    "resource": {"group":"apps","version":"v1","resource":"deployments"},
    # subresource, if the request is to a subresource
    "subResource": "scale",

    # Fully-qualified group/version/kind of the incoming object in the original request to the API server.
    # This only differs from `kind` if the webhook specified `matchPolicy: Equivalent` and the 
    # original request to the API server was converted to a version the webhook registered for.
    "requestKind": {"group":"autoscaling","version":"v1","kind":"Scale"},
    # Fully-qualified group/version/kind of the resource being modified in the original request to the API server.
    # This only differs from `resource` if the webhook specified `matchPolicy: Equivalent` and the 
    # original request to the API server was converted to a version the webhook registered for.
    "requestResource": {"group":"apps","version":"v1","resource":"deployments"},
    # subresource, if the request is to a subresource
    # This only differs from `subResource` if the webhook specified `matchPolicy: Equivalent` and the 
    # original request to the API server was converted to a version the webhook registered for.
    "requestSubResource": "scale",

    # Name of the resource being modified
    "name": "my-deployment",
    # Namespace of the resource being modified, if the resource is namespaced (or is a Namespace object)
    "namespace": "my-namespace",

    # operation can be CREATE, UPDATE, DELETE, or CONNECT
    "operation": "UPDATE",

    "userInfo": {
      # Username of the authenticated user making the request to the API server
      "username": "admin",
      # UID of the authenticated user making the request to the API server
      "uid": "014fbff9a07c",
      # Group memberships of the authenticated user making the request to the API server
      "groups": ["system:authenticated","my-admin-group"],
      # Arbitrary extra info associated with the user making the request to the API server.
      # This is populated by the API server authentication layer and should be included
      # if any SubjectAccessReview checks are performed by the webhook.
      "extra": {
        "some-key":["some-value1", "some-value2"]
      }
    },

    # object is the new object being admitted.
    # It is null for DELETE operations.
    "object": {"apiVersion":"autoscaling/v1","kind":"Scale",...},
    # oldObject is the existing object.
    # It is null for CREATE and CONNECT operations.
    "oldObject": {"apiVersion":"autoscaling/v1","kind":"Scale",...},
    # options contains the options for the operation being admitted, like meta.k8s.io/v1 CreateOptions, UpdateOptions, or DeleteOptions.
    # It is null for CONNECT operations.
    "options": {"apiVersion":"meta.k8s.io/v1","kind":"UpdateOptions",...},

    # dryRun indicates the API request is running in dry run mode and will not be persisted.
    # Webhooks with side effects should avoid actuating those side effects when dryRun is true.
    # See http://k8s.io/docs/reference/using-api/api-concepts/#make-a-dry-run-request for more details.
    "dryRun": false
  }
}

{
  # Deprecated in v1.16 in favor of admission.k8s.io/v1
  "apiVersion": "admission.k8s.io/v1beta1",
  "kind": "AdmissionReview",
  "request": {
    # Random uid uniquely identifying this admission call
    "uid": "705ab4f5-6393-11e8-b7cc-42010a800002",

    # Fully-qualified group/version/kind of the incoming object
    "kind": {"group":"autoscaling","version":"v1","kind":"Scale"},
    # Fully-qualified group/version/kind of the resource being modified
    "resource": {"group":"apps","version":"v1","resource":"deployments"},
    # subresource, if the request is to a subresource
    "subResource": "scale",

    # Fully-qualified group/version/kind of the incoming object in the original request to the API server.
    # This only differs from `kind` if the webhook specified `matchPolicy: Equivalent` and the 
    # original request to the API server was converted to a version the webhook registered for.
    # Only sent by v1.15+ API servers.
    "requestKind": {"group":"autoscaling","version":"v1","kind":"Scale"},
    # Fully-qualified group/version/kind of the resource being modified in the original request to the API server.
    # This only differs from `resource` if the webhook specified `matchPolicy: Equivalent` and the 
    # original request to the API server was converted to a version the webhook registered for.
    # Only sent by v1.15+ API servers.
    "requestResource": {"group":"apps","version":"v1","resource":"deployments"},
    # subresource, if the request is to a subresource
    # This only differs from `subResource` if the webhook specified `matchPolicy: Equivalent` and the 
    # original request to the API server was converted to a version the webhook registered for.
    # Only sent by v1.15+ API servers.
    "requestSubResource": "scale",

    # Name of the resource being modified
    "name": "my-deployment",
    # Namespace of the resource being modified, if the resource is namespaced (or is a Namespace object)
    "namespace": "my-namespace",

    # operation can be CREATE, UPDATE, DELETE, or CONNECT
    "operation": "UPDATE",

    "userInfo": {
      # Username of the authenticated user making the request to the API server
      "username": "admin",
      # UID of the authenticated user making the request to the API server
      "uid": "014fbff9a07c",
      # Group memberships of the authenticated user making the request to the API server
      "groups": ["system:authenticated","my-admin-group"],
      # Arbitrary extra info associated with the user making the request to the API server.
      # This is populated by the API server authentication layer and should be included
      # if any SubjectAccessReview checks are performed by the webhook.
      "extra": {
        "some-key":["some-value1", "some-value2"]
      }
    },

    # object is the new object being admitted.
    # It is null for DELETE operations.
    "object": {"apiVersion":"autoscaling/v1","kind":"Scale",...},
    # oldObject is the existing object.
    # It is null for CREATE and CONNECT operations (and for DELETE operations in API servers prior to v1.15.0)
    "oldObject": {"apiVersion":"autoscaling/v1","kind":"Scale",...},
    # options contains the options for the operation being admitted, like meta.k8s.io/v1 CreateOptions, UpdateOptions, or DeleteOptions.
    # It is null for CONNECT operations.
    # Only sent by v1.15+ API servers.
    "options": {"apiVersion":"meta.k8s.io/v1","kind":"UpdateOptions",...},

    # dryRun indicates the API request is running in dry run mode and will not be persisted.
    # Webhooks with side effects should avoid actuating those side effects when dryRun is true.
    # See http://k8s.io/docs/reference/using-api/api-concepts/#make-a-dry-run-request for more details.
    "dryRun": false
  }
}

响应

Webhooks 会以 200 HTTP 状态代码Content-Type:application/json响应,以及包含AdmissionReview对象的xaingy(与发送的版本相同), 带有response节的序列,并序列化为 JSON。

response节至少必须包含以下字段: *uid,从发送到 webhook 的request.uid复制而来 *allowed,设置为truefalse

Webhook 允许请求的最简单响应示例:

{
  "apiVersion": "admission.k8s.io/v1",
  "kind": "AdmissionReview",
  "response": {
    "uid": "<value from request.uid>",
    "allowed": true
  }
}

{
  "apiVersion": "admission.k8s.io/v1beta1",
  "kind": "AdmissionReview",
  "response": {
    "uid": "<value from request.uid>",
    "allowed": true
  }
}

Webhook 禁止请求的最简单响应示例:

{
  "apiVersion": "admission.k8s.io/v1",
  "kind": "AdmissionReview",
  "response": {
    "uid": "<value from request.uid>",
    "allowed": false
  }
}

{
  "apiVersion": "admission.k8s.io/v1beta1",
  "kind": "AdmissionReview",
  "response": {
    "uid": "<value from request.uid>",
    "allowed": false
  }
}

当拒绝请求时,webhook 可以使用status字段自定义http代码和消息体返回给用户。 指定的状态对象返回给用户。有关状态类型的详细信息,请参见 API 文档。 禁止请求,定制 HTTP 状态代码和显示给用户的消息的响应示例:

{
  "apiVersion": "admission.k8s.io/v1",
  "kind": "AdmissionReview",
  "response": {
    "uid": "<value from request.uid>",
    "allowed": false,
    "status": {
      "code": 403,
      "message": "You cannot do this because it is Tuesday and your name starts with A"
    }
  }
}

{
  "apiVersion": "admission.k8s.io/v1beta1",
  "kind": "AdmissionReview",
  "response": {
    "uid": "<value from request.uid>",
    "allowed": false,
    "status": {
      "code": 403,
      "message": "You cannot do this because it is Tuesday and your name starts with A"
    }
  }
}

当允许请求时,变异接纳 Webhook 也可以选择修改传入对象。这是通过在响应中使用patchpatchType字段来完成的。 当前唯一支持的patchTypeJSONPatch。有关更多详细信息,请参见 JSON 补丁 文档。 对于patchType:JSONPatchpatch字段包含一个以 base64 编码的 JSON 补丁操作数组。

例如,设置spec.replicas的单个补丁操作将是[{"op":"add","path":"/spec/replicas","value":3}]]

以 Base64 编码,这将是W3sib3AiOiAiYWRkIiwgInBhdGgiOiAiL3NwZWMvcmVwbGljYXMiLCAidmFsdWUiOiAzfV0=

因此,添加该标签的 webhook 响应为:

{
  "apiVersion": "admission.k8s.io/v1",
  "kind": "AdmissionReview",
  "response": {
    "uid": "<value from request.uid>",
    "allowed": true,
    "patchType": "JSONPatch",
    "patch": "W3sib3AiOiAiYWRkIiwgInBhdGgiOiAiL3NwZWMvcmVwbGljYXMiLCAidmFsdWUiOiAzfV0="
  }
}

{
  "apiVersion": "admission.k8s.io/v1beta1",
  "kind": "AdmissionReview",
  "response": {
    "uid": "<value from request.uid>",
    "allowed": true,
    "patchType": "JSONPatch",
    "patch": "W3sib3AiOiAiYWRkIiwgInBhdGgiOiAiL3NwZWMvcmVwbGljYXMiLCAidmFsdWUiOiAzfV0="
  }
}

Webhook-配置

要注册 admssion webhook,请创建MutatingWebhookConfigurationValidatingWebhookConfiguration API 对象。

每种配置可以包含一个或多个 Web 钩子。如果在单个配置中指定了多个 webhook,则应为每个 webhook 赋予一个唯一的名称。 这在admissionregistration.k8s.io/v1中是必需的,但在使用admissionregistration.k8s.io/v1beta1时强烈建议, 为了使生成的审核日志和指标更易于与活动配置匹配。

每个 Webhook 定义以下内容。

匹配请求-规则

每个 Webhook 必须指定用于确定是否应将对 apiserver 的请求发送到 Webhook 的规则列表。 每个规则都指定一个或多个操作,apiGroups,apiVersions 和资源以及资源范围:

*operations列出一个或多个要匹配的操作。可以是CREATEUPDATEDELETECONNECT* 以匹配所有内容。

*apiGroups列出了一个或多个要匹配的 API 组。`是核心 API 组。*` 匹配所有 API 组。

*apiVersions列出了一个或多个要匹配的 API 版本。* 匹配所有 API 版本。

*resources列出了一个或多个要匹配的资源。 **匹配所有资源,但不匹配子资源。 **/* 匹配所有资源和子资源。 *pod/* 匹配 pod 的所有子资源。 **/status 匹配所有状态子资源。

*scope指定要匹配的范围。有效值为ClusterNamespaced*。子资源匹配其父资源的范围。在 v1.14+ 中受支持。默认值为*,匹配 1.14 之前的行为。 *Cluster表示只有群集作用域的资源才能匹配此规则(名称空间 API 对象是群集作用域的)。 *Namespaced意味着只有命名空间资源才符合此规则。 ** 表示没有范围限制。

如果传入请求与任何 Webhook 规则的指定操作,组,版本,资源和范围匹配,则该请求将发送到 Webhook。

以下是可用于指定应拦截哪些资源的规则的其他示例。

CREATEUPDATE请求匹配到apps/v1apps/v1beta1deploymentsreplicasets

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  rules:
  - operations: ["CREATE", "UPDATE"] 
    apiGroups: ["apps"]
    apiVersions: ["v1", "v1beta1"]
    resources: ["deployments", "replicasets"]
    scope: "Namespaced"
  ...

# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  rules:
  - operations: ["CREATE", "UPDATE"] 
    apiGroups: ["apps"]
    apiVersions: ["v1", "v1beta1"]
    resources: ["deployments", "replicasets"]
    scope: "Namespaced"
  ...

匹配所有 API 组和版本中的所有资源(但不包括子资源)的创建请求:

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  rules:
  - operations: ["CREATE"]
    apiGroups: ["*"]
    apiVersions: ["*"]
    resources: ["*"]
    scope: "*"
  ...

# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  rules:
  - operations: ["CREATE"]
    apiGroups: ["*"]
    apiVersions: ["*"]
    resources: ["*"]
    scope: "*"
  ...

Match update requests for all status subresources in all API groups and versions:

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  rules:
  - operations: ["UPDATE"]
    apiGroups: ["*"]
    apiVersions: ["*"]
    resources: ["*/status"]
    scope: "*"
  ...

# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  rules:
  - operations: ["UPDATE"]
    apiGroups: ["*"]
    apiVersions: ["*"]
    resources: ["*/status"]
    scope: "*"
  ...

Matching requests: objectSelector

匹配请求-对象选择器

在v1.15 +中,基于Web服务的标签,webhook 可以选择限制拦截哪些请求 通过指定一个 objectSelector 来发送它们的对象。如果指定,则为 objectSelector同时针对将要发送到Webhook的对象和oldObject进行评估, 并且如果两个对象中的任何一个与选择器都匹配,则视为匹配。

空对象(对于 create 而言为 oldObject,对于 delete 而言为 newObject), 或没有标签的对象(例如 DeploymentDeployRollback 或 PodProxyOptions 对象) 被认为不匹配。

仅在选择加入 Webhook 时才使用对象选择器,因为最终用户可以通过设置标签来跳过 admission Webhook。

这个例子展示了一个可变的 webhook,它将匹配带有标签foo:bar的任何资源的CREATE

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  objectSelector:
    matchLabels:
      foo: bar
  rules:
  - operations: ["CREATE"]
    apiGroups: ["*"]
    apiVersions: ["*"]
    resources: ["*"]
    scope: "*"
  ...

# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1
apiVersion: admissionregistration.k8s.io/v1beta1
kind: MutatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  objectSelector:
    matchLabels:
      foo: bar
  rules:
  - operations: ["CREATE"]
    apiGroups: ["*"]
    apiVersions: ["*"]
    resources: ["*"]
    scope: "*"
  ...

有关标签选择器的更多示例,请参见 更多

匹配请求-命名空间选择器

Webhooks 可以选择限制拦截对命名空间资源的请求, 通过指定namespaceSelector,基于包含名称空间的标签。

namespaceSelector 命名空间选择器决定是否在对命名空间资源的请求上运行 webhook(或命名空间对象),取决于命名空间的标签是否与选择器匹配。 如果对象本身是名称空间,则对object.metadata.labels执行匹配。 如果对象是除命名空间以外的群集范围内的资源,则namespaceSelector无效。

这个例子展示了一个可变的webhook,它匹配命名空间内任何命名空间资源的CREATE 没有01runlevel标签:

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  namespaceSelector:
    matchExpressions:
    - key: runlevel
      operator: NotIn
      values: ["0","1"]
  rules:
  - operations: ["CREATE"]
    apiGroups: ["*"]
    apiVersions: ["*"]
    resources: ["*"]
    scope: "Namespaced"
  ...

# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1
apiVersion: admissionregistration.k8s.io/v1beta1
kind: MutatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  namespaceSelector:
    matchExpressions:
    - key: runlevel
      operator: NotIn
      values: ["0","1"]
  rules:
  - operations: ["CREATE"]
    apiGroups: ["*"]
    apiVersions: ["*"]
    resources: ["*"]
    scope: "Namespaced"
  ...

此示例显示了一个验证 Webhook,该 Webhook 与名称空间内任何名称空间资源的CREATE匹配 与产品阶段环境相关联:

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  namespaceSelector:
    matchExpressions:
    - key: environment
      operator: In
      values: ["prod","staging"]
  rules:
  - operations: ["CREATE"]
    apiGroups: ["*"]
    apiVersions: ["*"]
    resources: ["*"]
    scope: "Namespaced"
  ...

# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  namespaceSelector:
    matchExpressions:
    - key: environment
      operator: In
      values: ["prod","staging"]
  rules:
  - operations: ["CREATE"]
    apiGroups: ["*"]
    apiVersions: ["*"]
    resources: ["*"]
    scope: "Namespaced"
  ...

有关标签选择器的更多示例,请参见 更多

匹配请求-策略匹配

apiserver 可以通过多个 API 组或版本使对象可用。 例如,Kubernetes apiserver 允许创建和修改Deployment对象 通过 extensions/v1beta1apps/v1beta1apps/v1beta2apps/v1 APIs 进行。

例如,如果一个 Webhook 仅为某些Api groups/version指定了规则(例如apiGroups:["apps"]apiVersions:[v1,v1beta1]), 并提出了通过另一个Api groups/version(例如extensions/v1beta1)修改资源的请求, 该请求将不会发送到 Webhook。

在 v1.15+ 中,matchPolicy允许 webhook 定义如何使用其rules匹配传入的请求。 允许的值为ExactEquivalent

*Exact表示仅当请求与指定规则完全匹配时才应拦截该请求。 *Equivalent表示如果修改了rules中列出的资源,即使通过另一个Api groups/version,也应拦截请求。

在上面给出的示例中,仅为apps/v1注册的 webhook 可以使用matchPolicymatchPolicy:Exact表示将不会将extensions/v1beta1请求发送到 Webhook *matchPolicy:Equivalent意味着将extensions/v1beta1请求发送到 webhook(将对象转换为 webhook 指定的版本:apps/v1

建议指定Equivalent,并确保 Webhook 继续拦截他们期望在升级时启用 apiserver 中资源的新版本的资源。

当资源停止由 apiserver 提供服务时,它不再被视为等同于仍在提供服务的该资源的其他版本。 例如,计划在 v1.16 中默认停止使用已弃用的extensions/v1beta1部署。 一旦发生,带有apiGroups:["extensions"]apiVersions:["v1beta1"]resources:["deployments"]规则的 webhook 将不再拦截通过apps/v1 API 创建的部署。因此,webhooks 应该更优先注册用于稳定版本的资源。

此示例显示了一个验证 Webhook,该 Webhook 拦截对部署的修改(无论 API 组或版本), 并始终会发送一个apps/v1部署对象:

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  matchPolicy: Equivalent
  rules:
  - operations: ["CREATE","UPDATE","DELETE"]
    apiGroups: ["apps"]
    apiVersions: ["v1"]
    resources: ["deployments"]
    scope: "Namespaced"
  ...

使用admissionregistration.k8s.io/v1创建的 admission webhhok 默认为Equivalent

# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  matchPolicy: Equivalent
  rules:
  - operations: ["CREATE","UPDATE","DELETE"]
    apiGroups: ["apps"]
    apiVersions: ["v1"]
    resources: ["deployments"]
    scope: "Namespaced"
  ...

使用admissionregistration.k8s.io/v1beta1创建的 admission webhhok 默认为Exact

调用 Webhook

apiserver 确定请求应发送到 Webhook 后, 它需要知道如何调用 Webhook。这在clientConfig中指定 webhook 配置的节。

可以通过 URL 或服务引用来调用 Webhooks,并且可以选择包含自定义 CA 包,以用于验证 TLS 连接。

URL

url以标准URL形式给出webhook的位置(scheme://host:port/path)。

host不应引用集群中运行的服务;采用通过指定service字段来提供服务引用。主机可以通过某些 apiserver 中的外部 DNS 进行解析 (例如,kube-apiserver无法解析集群内 DNS 违反分层规则)。主机也可以是IP地址。

请注意,将 localhost 或 127.0.0.1 用作主机是除非您非常小心在所有主机上运行此 Webhook,否则风险很大 运行一个 apiserver 可能需要对此进行调用 webhook。这样的安装很可能是不可移植的,即不容易出现在新集群中。

方案必须为https; URL 必须以https://开头。

尝试使用用户或基本身份验证,例如不允许使用user:password@。片段(#...)和查询参数(?...)也不允许。

这是配置为调用 URL 的可变 Webhook 的示例(并且期望使用系统信任根来验证 TLS 证书,因此不指定 caBundle):

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  clientConfig:
    url: "https://my-webhook.example.com:9443/my-webhook-path"
  ...

# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1
apiVersion: admissionregistration.k8s.io/v1beta1
kind: MutatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  clientConfig:
    url: "https://my-webhook.example.com:9443/my-webhook-path"
  ...

服务参考

clientConfig 内部的 service 节是对该 Webhook 服务的引用。如果 Webhook 在集群中运行,则应使用service而不是url。 服务名称空间和名称是必需的。端口是可选的,默认为 443。该路径是可选的,默认为/

这是配置为在端口1234上调用服务的可变 Webhook 的示例在子路径/my-path下,并针对 ServerName 验证 TLS 连接 使用自定义 CA 包的my-service-name.my-service-namespace.svc

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  clientConfig:
    caBundle: "Ci0tLS0tQk...<base64-encoded PEM bundle containing the CA that signed the webhook's serving certificate>...tLS0K"
    service:
      namespace: my-service-namespace
      name: my-service-name
      path: /my-path
      port: 1234
  ...

# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1
apiVersion: admissionregistration.k8s.io/v1beta1
kind: MutatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  clientConfig:
    caBundle: "Ci0tLS0tQk...<base64-encoded PEM bundle containing the CA that signed the webhook's serving certificate>...tLS0K"
    service:
      namespace: my-service-namespace
      name: my-service-name
      path: /my-path
      port: 1234
  ...

副作用

Webhook 通常只对发送给他们的AdmissionReview的内容起作用。 但是,某些 Webhook 在处理接纳请求时会进行带外更改。

进行带外更改(副作用)的 Webhooks 也必须具有协调机制(如控制器)定期确定世界的实际状态并进行调整录入 Webhook 修改的带外数据以反映现实情况。 这是因为对 admission Webhook 的调用不能保证所准入的对象将原样保留或完全保留。后来的 webhook 可以修改对象的内容,在写入存储设备时可能会发生冲突, 否则服务器可以在持久保存对象之前关闭电源。

另外,当处理dryRun:true接纳请求时,具有副作用的 webhooks 必须跳过那些副作用。 一个webhook必须明确指出在使用dryRun运行时不会产生副作用, 否则试运行请求将不会发送到 Webhook,而 API 请求将失败。

Webhooks 使用 webhook 配置中的sideEffects字段指示它们是否有副作用: *Unknown:未知有关调用 Webhook 的副作用的信息。 如果带有dryRun:true的请求将触发对该 Webhook 的调用,则该请求将失败,并且不会调用该 Webhook。 *None:调用 webhook 不会有副作用。 *Some:调用 webhook 可能会有副作用。 如果具有 dry-run 属性的请求将触发对此 Webhook 的调用,则该请求将失败,并且不会调用该 Webhook。 *NoneOnDryRun:调用 webhook 可能会有副作用, 但是如果将带有dryRun:true的请求发送到 Webhook,则该 Webhook 将抑制副作用(该 Webhook 可识别dryRun)。

允许值: *在admissionregistration.k8s.io/v1beta1中,sideEffects可以设置为UnknownNoneSome,或者NoneOnDryRun,并且默认为Unknown。 *在admissionregistration.k8s.io/v1中,sideEffects必须设置为NoneNoneOnDryRun

这是一个验证 webhook 的示例,表明它对dryRun:true请求没有副作用:

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  sideEffects: NoneOnDryRun
  ...

# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  sideEffects: NoneOnDryRun
  ...

超时

由于 Webhooks 会增加 API 请求的延迟,因此应尽快评估。timeoutSeconds 允许配置 apiserver 等待 Webhook 响应的时间在将通话视为失败之前。

如果超时在 Webhook 响应之前到期,则 Webhook 调用将被忽略或 API 调用将基于 失败策略 被拒绝。

超时值必须在 1 到 30 秒之间。

这是一个自定义超时为 2 秒的验证 Webhook 的示例:

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  timeoutSeconds: 2
  ...

使用admissionregistration.k8s.io/v1创建的 admission Webhook 默认超时为 10 秒。

# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  timeoutSeconds: 2
  ...

使用admissionregistration.k8s.io/v1创建的 admission Webhook 默认超时为 30 秒。

撤销策略

可变准入插件(包括 Webhooks)的单次订购不适用于所有情况(例如,请参见 更多。可变的 Webhook 可以添加新的子结构 到对象(例如向pod中添加container),以及其他已经运行可能会对这些新结构有影响(例如在所有容器上设置imagePullPolicy)。

在 v1.15+ 中,允许准入插件观察到其他插件所做的更改,如果可变的 Webhook 修改了一个对象,则会重新运行内置的可变准入插件, 并且可变的 Webhook 可以指定reinvocationPolicy来控制是否也重新调用它们。

可以将reinvocationPolicy设置为Never或者IfNeeded. 默认为Never.。

*Never:Webhook 在一次接纳评估中不得被多次调用 *IfNeeded:如果对象被接纳,则可以再次调用 Webhook 作为准入评估的一部分 最初的 webhook 调用之后,其他准入插件会被修改。

要注意的重要元素是:

*附加调用的数量不能保证完全是一个。 *如果其他调用导致对该对象的进一步修改,则不能保证再次调用 webhooks。 *使用此选项的 Webhook 可能会重新排序,以最大程度地减少其他调用。 *要在所有可变都保证完成后验证对象,请改用 验证 admission Webhook(建议对有副作用的 Webhook 使用)。

这是一个可变的 webhook 选择在以后的准入插件修改对象时重新调用的示例:

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  reinvocationPolicy: IfNeeded
  ...

# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1
apiVersion: admissionregistration.k8s.io/v1beta1
kind: MutatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  reinvocationPolicy: IfNeeded
  ...

可变的 Webhook 必须是 幂等,能够成功处理他们已经允许的对象并可能进行修改。可变的 Webhook 都是如此,因为它们可以 进行任何更改用户提供的对象中可能已经存在一个对象,但是对于选择重新调用的 Webhook 来说这是必不可少的。

失败策略

failurePolicy定义了来自 admission webhook 的无法识别的错误和超时错误被处理。允许的值为Ignore或者Fail

*Ignore意味着调用 webhook 的错误将被忽略并且允许 API 请求继续。 *Fail表示调用 webhook 的错误导致准入失败并且 API 请求被拒绝。

这是一个变异的 Webhook,配置为在调用接纳 Webhook 遇到错误时拒绝 API 请求:

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  failurePolicy: Fail
  ...

使用admissionregistration.k8s.io/v1创建的 admission Webhook 将默认failurePolicy设置为Fail

# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1
apiVersion: admissionregistration.k8s.io/v1beta1
kind: MutatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  failurePolicy: Fail
  ...

使用admissionregistration.k8s.io/v1创建的 admission Webhook 将默认failurePolicy设置为Ignore

监控 Admission Webhook

apiserver 提供了监控 admission Webhook 行为的方法。这些监控机制可帮助集群管理员回答以下问题:

  1. 哪个可变 webhook 使 API 请求中的对象变化?

  2. 可变 webhook 应用于对象有什么变化?

  3. 哪些 webhook 经常拒绝 API 请求?是什么原因拒绝?

更改 Webhook 审核注释

有时候了解API要求中的哪个可变 webhook 修改了对象,以及 webhook 适用。

在 v1.16+ 中,kube-apiserver 在每个可变的 Webhook 上执行 auditing调用。每次调用都会生成审核注释 捕获请求对象是否因调用而发生了变化,并可选地生成注释来捕获应用的对象来自 Webhook 接纳响应的补丁。在审核事件中为注释的给定阶段的给定请求设置注释。 它的执行,然后根据某种策略进行预处理,并写入后端。

事件的审核级别确定要记录哪些注释:

  • Metadata审核级别或更高级别,带有键的注释mutation.webhook.admission.k8s.io/round_{round idx} _index_ {order idx}记录了 JSON 有效负载,表明 Webhook 会针对给定的请求以及是否更改了对象而被调用。

例如,对于正在被重新调用的 Webhook,记录了以下注释。Webhook 在更改 webhook 链,并且在调用期间未更改请求对象。

# the audit event recorded
{
    "kind": "Event",
    "apiVersion": "audit.k8s.io/v1",
    "annotations": {
        "mutation.webhook.admission.k8s.io/round_1_index_2": "{\"configuration\":\"my-mutating-webhook-configuration.example.com\",\"webhook\":\"my-webhook.example.com\",\"mutated\": false}"
        # other annotations
        ...
    }
    # other fields
    ...
}
# the annotation value deserialized
{
    "configuration": "my-mutating-webhook-configuration.example.com",
    "webhook": "my-webhook.example.com",
    "mutated": false
}

The following annotatino gets recorded for a webhook being invoked in the first round. The webhook is ordered the first in
the mutating webhook chain, and mutated the request object during the invocation.

# the audit event recorded
{
    "kind": "Event",
    "apiVersion": "audit.k8s.io/v1",
    "annotations": {
        "mutation.webhook.admission.k8s.io/round_0_index_0": "{\"configuration\":\"my-mutating-webhook-configuration.example.com\",\"webhook\":\"my-webhook-always-mutate.example.com\",\"mutated\": true}"
        # other annotations
        ...
    }
    # other fields
    ...
}
# the annotation value deserialized
{
    "configuration": "my-mutating-webhook-configuration.example.com",
    "webhook": "my-webhook-always-mutate.example.com",
    "mutated": true
}
  • At Request audit level or higher, an annotation with key patch.webhook.admission.k8s.io/round_{round idx}_index_{order idx} gets logged with JSON payload indicating a webhook gets invoked for given request and what patch gets applied to the request object.

For example, the following annotation gets recorded for a webhook being reinvoked. The webhook is ordered the fourth in the mutating webhook chain, and responded with a JSON patch which got applied to the request object.

# the audit event recorded
{
    "kind": "Event",
    "apiVersion": "audit.k8s.io/v1",
    "annotations": {
        "patch.webhook.admission.k8s.io/round_1_index_3": "{\"configuration\":\"my-other-mutating-webhook-configuration.example.com\",\"webhook\":\"my-webhook-always-mutate.example.com\",\"patch\":[{\"op\":\"add\",\"path\":\"/data/mutation-stage\",\"value\":\"yes\"}],\"patchType\":\"JSONPatch\"}"
        # other annotations
        ...
    }
    # other fields
    ...
}
# the annotation value deserialized
{
    "configuration": "my-other-mutating-webhook-configuration.example.com",
    "webhook": "my-webhook-always-mutate.example.com",
    "patchType": "JSONPatch",
    "patch": [
        {
            "op": "add",
            "path": "/data/mutation-stage",
            "value": "yes"
        }
    ]
}

Amission webhook 监控指标

Kube-apiserver 从/metrics端点公开 Prometheus 指标,可用于监控和诊断 apiserver 状态。以下指标记录与准入网络挂钩相关的状态。

Apiserver Admission Webhook 拒绝次数

有时,了解哪些 Admission Webhook 经常拒绝 API 请求非常有用,并且拒绝的原因。

在 v1.16+ 中,kube-apiserver 公开了 Prometheus 计数器度量记录 Admission Webhook 拒绝。度量标准被标记为识别 Webhook 拒绝的原因:

-name:拒绝请求 Webhook 的名称。 -operation:请求的操作类型,可以是CREATE之一,更新,删除和连接。 -type:Admission webhook 类型,可以是admitvalidating中的一种。 -error_type:标识在 webhook 调用期间是否发生了错误导致了拒绝。其值可以是以下之一: -calling_webhook_error:发生了来自Admission Webhook 的无法识别的错误或超时错误,并且 webhook 的 失败策略 设置为Fail。 -no_error:未发生错误。Webhook 在准入中以allowed:false拒绝了请求响应。 度量标签rejection_code记录了在准入响应中设置的.status.code。 -apiserver_internal_error:发生 apiserver 内部错误。 -rejection_code:在以下情况下在准入响应中设置的 HTTP 状态代码 webhook 拒绝了请求。

<– Example of the rejection count metrics: –>

拒绝计数指标示例:

# HELP apiserver_admission_webhook_rejection_count [ALPHA] Admission webhook rejection count, identified by name and broken out for each admission type (validating or admit) and operation. Additional labels specify an error type (calling_webhook_error or apiserver_internal_error if an error occurred; no_error otherwise) and optionally a non-zero rejection code if the webhook rejects the request with an HTTP status code (honored by the apiserver when the code is greater or equal to 400). Codes greater than 600 are truncated to 600, to keep the metrics cardinality bounded.
# TYPE apiserver_admission_webhook_rejection_count counter
apiserver_admission_webhook_rejection_count{error_type="calling_webhook_error",name="always-timeout-webhook.example.com",operation="CREATE",rejection_code="0",type="validating"} 1
apiserver_admission_webhook_rejection_count{error_type="calling_webhook_error",name="invalid-admission-response-webhook.example.com",operation="CREATE",rejection_code="0",type="validating"} 1
apiserver_admission_webhook_rejection_count{error_type="no_error",name="deny-unwanted-configmap-data.example.com",operation="CREATE",rejection_code="400",type="validating"} 13

最佳实践和警告

幂等

一个幂等的可变 Admission Webhook 能够成功处理它已经被接纳的对象并可能进行修改。可以多次应用准入,而不会改变结果初始应用程序。

幂等可变 Webhook 的示例:

  1. 对于CREATE Pod 请求,请设置以下字段的.spec.securityContext.runAsNonRoot字段:转换为true,以实施安全性最佳做法。

  2. 对于CREATE Pod 请求,如果字段.spec.containers[].resources.limits未设置容器的容器,请设置默认资源限制。

  3. 对于CREATE Pod 请求,如果尚不存在名称为foo-sidecar的容器,则注入名称为foo-sidecar的边车容器。

在上述情况下,可以安全地重新调用 Webhook,或接受已设置字段的对象。

非幂等可变 Admission Webhooks 的示例:

1.对于CREATE pod 请求,注入一个名为foo-sidecar的边车容器当前时间戳后缀(例如foo-sidecar-19700101-000000)。

2.对于CREATE/UPDATE pod 请求,如果设置了标签env,则拒绝该请求,否则,将env:prod标签添加到标签组中。

3.对于CREATE pod 请求,附加一个名为foo-sidecar的 sidecar 容器而无需查看是否已经有foo-sidecar容器。

在上述第一种情况下,重新调用 Webhook 可能导致同一侧边车每次被多次注入 Pod 使用不同的容器名称。同样,如果 sidecar 已存在,则 webhook 可以注入重复的容器。

在上述第二种情况下,重新调用 Webhook 将导致 Webhook 自身输出失败。

在上述第三种情况下,重新调用 Webhook 将导致 pod 规范中的容器重复,这使得该请求无效,并被 apiserver 拒绝。

拦截对象的所有版本

建议通过设置.webhooks[].matchPolicy,Admission webhooks 应该始终拦截对象的所有版本。到Equivalent。建议 Admission Webhook 应该优先注册资源的稳定版本。 如果未能拦截对象的所有版本,则可能导致某些请求中的请求未实施准入策略版本。有关示例,请参见 匹配请求-策略匹配

可用性

建议 Admission webhook 尽快评估(通常以毫秒为单位),因为它们会增加 API 请求的延迟。期望对 Webhooks 使用较小的超时。有关更多详细信息,请参见 超时

建议 Admission Webhook 应该利用某种形式的负载平衡,以提供高可用性和性能优势。如果群集中正在运行 Webhook,则可以在服务后面运行多个 Webhook 后端利用服务支持的负载平衡。

确保看到对象的最终状态

需要确保他们看到对象的最终状态以实施策略的 Admission Webhook 应该使用一个有效的 Admission webhook,因为可以通过更改 webhooks 看到对象后对其进行修改。

例如,一个可变 Webhook 配置为在每个容器上注入一个名称为foo-sidecar的边车容器。 CREATEpod 请求。如果*必须*提供 sidecar,则还应该配置一个有效的 Admission webhook 来拦截CREATE pod 请求并进行验证 在要创建的对象中存在一个具有预期配置的名称为foo-sidecar的容器。

避免自托管的 Webhooks 中出现死锁

如果配置了群集,则在群集内运行的 Webhook 可能会导致死锁拦截启动自己的 Pod 所需的资源。

例如,可变 Admission Webhook 被配置为仅当在标签中设置了某个标签时才接纳CREATE pod 请求(例如env:prod)。Webhook 服务器在未设置env标签的部署中运行。 当运行 Webhook 服务器 Pod 的节点变得不正常后,webhook 部署将尝试将 Pod 重新安排到另一个节点。但是请求将 因为未设置env标签,所以现有的 webhook 服务器拒绝了它,并且无法进行迁移。

建议使用 namespaceSelector 排除运行 Webhook 的名称空间。

Side Effects

建议 Admission Webhook 尽可能避免副作用,这意味着 Webhook 只能在发送给他们的AdmissionReview的内容,请勿进行带外更改。如果 Webhook 没有任何副作用,将.webhooks[].sideEffects字段应设置为None

如果在准入评估过程中需要副作用,则在处理 AdmissionReview 对象将DryRun设置为true,并将.webhooks[].sideEffects字段设置为NoneOnDryRun。有关更多详细信息,请参见 副作用

避免对 kube-system 名称空间进行操作

kube-system名称空间包含由 Kubernetes 系统创建的对象,例如服务负责控制平面组件,如kube-dns之类的 Pod。 意外地更改或拒绝kube-system名称空间中的请求导致控制平面组件停止运行或引入未知行为。 如果您的 Webhook 不打算修改控制平面上 Kubernetes 的行为,将kube-system命名空间排除在使用 命名空间选择器

反馈