From 79364dad1145ae9fad78c5c43ffbdf5584266be7 Mon Sep 17 00:00:00 2001 From: Akihito INOH Date: Wed, 23 Jun 2021 14:35:44 +0900 Subject: [PATCH 001/102] Add script to print URLs updated by target PR --- scripts/get-changed-urls.sh | 48 +++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100755 scripts/get-changed-urls.sh diff --git a/scripts/get-changed-urls.sh b/scripts/get-changed-urls.sh new file mode 100755 index 0000000000..4ccb57d7e1 --- /dev/null +++ b/scripts/get-changed-urls.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +# This script lists URLs changed by the target PR. You can jump to target page quickly by clicking those. +# Syntax: get-changed-urls.sh [] +# Example: +# $ get-changed-urls.sh 28542 +# http://localhost:1313/ja/docs/concepts/configuration/manage-resources-containers +# http://localhost:1313/ja/docs/concepts/policy/limit-range +# http://localhost:1313/ja/docs/concepts/policy/resource-quotas +# http://localhost:1313/ja/docs/reference/command-line-tools-reference/feature-gates +# http://localhost:1313/ja/docs/setup/best-practices/cluster-large +# +# If no is passed, it will assume "http://localhost:1313". +# It's the default endpoint for "make container-serve" or "make serve". +# Please look at the README(https://github.com/kubernetes/website#using-this-repository) to serve endpoint. +# Or you can pass any strings to . +# You can get URLs for upstream by passing as "https://kubernetes.io". + +set -e + +if [[ ${1} == "" ]] +then + echo "This script prints all URLs updated by target PR number." + echo "You can jump to updated pages quickly when PR review." + echo "This is intended for using with \"make container-serve\"." + echo "" + echo "Syntax: get-changed-urls.sh []" + echo "Example: get-changed-urls.sh 12345" + echo "If no is passed, it will assume \"http://localhost:1313\"" + exit 1 +fi + +PAGE_TOP=${2:-"http://localhost:1313"} + +GITHUB_REPOSITORY="kubernetes/website" +PR_NUM=${1} + +# URL for calling GitHub API +# For detail: https://docs.github.com/en/rest/reference/pulls#list-pull-requests-files +GITHUB_API_URL="https://api.github.com/repos/${GITHUB_REPOSITORY}/pulls/${PR_NUM}/files" + +# Get files included in target PR +URLS=$(curl --silent -X GET ${GITHUB_API_URL} | jq -r '.[].filename' | \ + sed -e "s/^content\/en//g" -e "s/^content//g" -e "s/.md$//g" | grep "docs" | xargs -I {} echo ${PAGE_TOP}{}) +for u in ${URLS} +do + echo ${u} +done From d97e53f2a174c922c7bbe9b4be28b2bd77832de6 Mon Sep 17 00:00:00 2001 From: Qiming Teng Date: Fri, 21 Jan 2022 16:28:21 +0800 Subject: [PATCH 002/102] [zh] Resync the configmap page --- .../docs/concepts/configuration/configmap.md | 77 ++++++++++--------- 1 file changed, 41 insertions(+), 36 deletions(-) diff --git a/content/zh/docs/concepts/configuration/configmap.md b/content/zh/docs/concepts/configuration/configmap.md index 47ceccda3f..2bb64570e9 100644 --- a/content/zh/docs/concepts/configuration/configmap.md +++ b/content/zh/docs/concepts/configuration/configmap.md @@ -77,8 +77,8 @@ ConfigMap 是一个 API [对象](/zh/docs/concepts/overview/working-with-objects 让你可以存储其他对象所需要使用的配置。 和其他 Kubernetes 对象都有一个 `spec` 不同的是,ConfigMap 使用 `data` 和 `binaryData` 字段。这些字段能够接收键-值对作为其取值。`data` 和 `binaryData` -字段都是可选的。`data` 字段设计用来保存 UTF-8 字节序列,而 `binaryData` 则 -被设计用来保存二进制数据作为 base64 编码的字串。 +字段都是可选的。`data` 字段设计用来保存 UTF-8 字节序列,而 `binaryData` +则被设计用来保存二进制数据作为 base64 编码的字串。 ConfigMap 的名字必须是一个合法的 [DNS 子域名](/zh/docs/concepts/overview/working-with-objects/names#dns-subdomain-names)。 @@ -92,11 +92,11 @@ Starting from v1.19, you can add an `immutable` field to a ConfigMap definition to create an [immutable ConfigMap](#configmap-immutable). --> `data` 或 `binaryData` 字段下面的每个键的名称都必须由字母数字字符或者 -`-`、`_` 或 `.` 组成。在 `data` 下保存的键名不可以与在 `binaryData` 下 -出现的键名有重叠。 +`-`、`_` 或 `.` 组成。在 `data` 下保存的键名不可以与在 `binaryData` +下出现的键名有重叠。 -从 v1.19 开始,你可以添加一个 `immutable` 字段到 ConfigMap 定义中,创建 -[不可变更的 ConfigMap](#configmap-immutable)。 +从 v1.19 开始,你可以添加一个 `immutable` 字段到 ConfigMap 定义中, +创建[不可变更的 ConfigMap](#configmap-immutable)。 ## ConfigMaps 和 Pods -你可以写一个引用 ConfigMap 的 Pod 的 `spec`,并根据 ConfigMap 中的数据 -在该 Pod 中配置容器。这个 Pod 和 ConfigMap 必须要在同一个 +你可以写一个引用 ConfigMap 的 Pod 的 `spec`,并根据 ConfigMap 中的数据在该 +Pod 中配置容器。这个 Pod 和 ConfigMap 必须要在同一个 {{< glossary_tooltip text="名字空间" term_id="namespace" >}} 中。 第四种方法意味着你必须编写代码才能读取 ConfigMap 和它的数据。然而, -由于你是直接使用 Kubernetes API,因此只要 ConfigMap 发生更改,你的 -应用就能够通过订阅来获取更新,并且在这样的情况发生的时候做出反应。 -通过直接进入 Kubernetes API,这个技术也可以让你能够获取到不同的名字空间 -里的 ConfigMap。 +由于你是直接使用 Kubernetes API,因此只要 ConfigMap 发生更改, +你的应用就能够通过订阅来获取更新,并且在这样的情况发生的时候做出反应。 +通过直接进入 Kubernetes API,这个技术也可以让你能够获取到不同的名字空间里的 ConfigMap。 下面是一个 Pod 的示例,它通过使用 `game-demo` 中的值来配置一个 Pod: @@ -243,16 +242,16 @@ definition specifies an `items` array in the `volumes` section. If you omit the `items` array entirely, every key in the ConfigMap becomes a file with the same name as the key, and you get 4 files. --> -ConfigMap 不会区分单行属性值和多行类似文件的值,重要的是 Pods 和其他对象 -如何使用这些值。 +ConfigMap 不会区分单行属性值和多行类似文件的值,重要的是 Pods +和其他对象如何使用这些值。 上面的例子定义了一个卷并将它作为 `/config` 文件夹挂载到 `demo` 容器内, 创建两个文件,`/config/game.properties` 和 `/config/user-interface.properties`, 尽管 ConfigMap 中包含了四个键。 这是因为 Pod 定义中在 `volumes` 节指定了一个 `items` 数组。 -如果你完全忽略 `items` 数组,则 ConfigMap 中的每个键都会变成一个与 -该键同名的文件,因此你会得到四个文件。 +如果你完全忽略 `items` 数组,则 ConfigMap 中的每个键都会变成一个与该键同名的文件, +因此你会得到四个文件。 ## 使用 ConfigMap {#using-configmaps} -ConfigMap 可以作为数据卷挂载。ConfigMap 也可被系统的其他组件使用,而 -不一定直接暴露给 Pod。例如,ConfigMap 可以保存系统中其他组件要使用 -的配置数据。 +ConfigMap 可以作为数据卷挂载。ConfigMap 也可被系统的其他组件使用, +而不一定直接暴露给 Pod。例如,ConfigMap 可以保存系统中其他组件要使用的配置数据。 你希望使用的每个 ConfigMap 都需要在 `spec.volumes` 中被引用到。 -如果 Pod 中有多个容器,则每个容器都需要自己的 `volumeMounts` 块,但针对 -每个 ConfigMap,你只需要设置一个 `spec.volumes` 块。 +如果 Pod 中有多个容器,则每个容器都需要自己的 `volumeMounts` 块,但针对每个 +ConfigMap,你只需要设置一个 `spec.volumes` 块。 ConfigMap 既可以通过 watch 操作实现内容传播(默认形式),也可实现基于 TTL 的缓存,还可以直接经过所有请求重定向到 API 服务器。 -因此,从 ConfigMap 被更新的那一刻算起,到新的主键被投射到 Pod 中去,这一 -时间跨度可能与 kubelet 的同步周期加上高速缓存的传播延迟相等。 +因此,从 ConfigMap 被更新的那一刻算起,到新的主键被投射到 Pod 中去, +这一时间跨度可能与 kubelet 的同步周期加上高速缓存的传播延迟相等。 这里的传播延迟取决于所选的高速缓存类型 (分别对应 watch 操作的传播延迟、高速缓存的 TTL 时长或者 0)。 @@ -391,6 +389,14 @@ ConfigMaps consumed as environment variables are not updated automatically and r 以环境变量方式使用的 ConfigMap 数据不会被自动更新。 更新这些数据需要重新启动 Pod。 +{{< note >}} + +将 ConfigMap 作为 [subPath](/docs/concepts/storage/volumes#using-subpath) +卷挂载的容器无法收到 ConfigMap 更新。 +{{< /note >}} + @@ -412,8 +418,8 @@ individual Secrets and ConfigMaps as immutable. For clusters that extensively us data has the following advantages: --> Kubernetes 特性 _不可变更的 Secret 和 ConfigMap_ 提供了一种将各个 -Secret 和 ConfigMap 设置为不可变更的选项。对于大量使用 ConfigMap 的 -集群(至少有数万个各不相同的 ConfigMap 给 Pod 挂载)而言,禁止更改 +Secret 和 ConfigMap 设置为不可变更的选项。对于大量使用 ConfigMap 的集群 +(至少有数万个各不相同的 ConfigMap 给 Pod 挂载)而言,禁止更改 ConfigMap 的数据有以下好处: - 保护应用,使之免受意外(不想要的)更新所带来的负面影响。 -- 通过大幅降低对 kube-apiserver 的压力提升集群性能,这是因为系统会关闭 - 对已标记为不可变更的 ConfigMap 的监视操作。 +- 通过大幅降低对 kube-apiserver 的压力提升集群性能, + 这是因为系统会关闭对已标记为不可变更的 ConfigMap 的监视操作。 此功能特性由 `ImmutableEphemeralVolumes` -[特性门控](/zh/docs/reference/command-line-tools-reference/feature-gates/) -来控制。你可以通过将 `immutable` 字段设置为 `true` 创建不可变更的 ConfigMap。 +[特性门控](/zh/docs/reference/command-line-tools-reference/feature-gates/)来控制。 +你可以通过将 `immutable` 字段设置为 `true` 创建不可变更的 ConfigMap。 例如: ```yaml @@ -454,8 +460,7 @@ to the deleted ConfigMap, it is recommended to recreate these pods. --> 一旦某 ConfigMap 被标记为不可变更,则 _无法_ 逆转这一变化,,也无法更改 `data` 或 `binaryData` 字段的内容。你只能删除并重建 ConfigMap。 -因为现有的 Pod 会维护一个对已删除的 ConfigMap 的挂载点,建议重新创建 -这些 Pods。 +因为现有的 Pod 会维护一个对已删除的 ConfigMap 的挂载点,建议重新创建这些 Pods。 ## {{% heading "whatsnext" %}} @@ -466,6 +471,6 @@ to the deleted ConfigMap, it is recommended to recreate these pods. separating code from configuration. --> * 阅读 [Secret](/zh/docs/concepts/configuration/secret/)。 -* 阅读 [配置 Pod 来使用 ConfigMap](/zh/docs/tasks/configure-pod-container/configure-pod-configmap/)。 -* 阅读 [Twelve-Factor 应用](https://12factor.net/) 来了解将代码和配置分开的动机。 +* 阅读[配置 Pod 使用 ConfigMap](/zh/docs/tasks/configure-pod-container/configure-pod-configmap/)。 +* 阅读 [Twelve-Factor 应用](https://12factor.net/zh_cn/)来了解将代码和配置分开的动机。 From 8dd6fa677db718a2c7451eed0333ec9a0007a6a0 Mon Sep 17 00:00:00 2001 From: Brett Wolmarans Date: Wed, 2 Mar 2022 09:21:06 -0800 Subject: [PATCH 003/102] --all-namespaces shorthand As a beginner to kubectl, I must have typed (and re-typed due to typos) --all-namespaces many hundreds of times before I stumbled across the -A shorthand notation for this. I sincerely would be grateful on behalf of all kubectl beginners if this very useful cheat could be added to this cheatsheet. I have proposed in this PR a location quite near the beginning of the cheatsheet for this so that it is very hard to miss. --- content/en/docs/reference/kubectl/cheatsheet.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/content/en/docs/reference/kubectl/cheatsheet.md b/content/en/docs/reference/kubectl/cheatsheet.md index b3c3536b31..cb3aa1f27b 100644 --- a/content/en/docs/reference/kubectl/cheatsheet.md +++ b/content/en/docs/reference/kubectl/cheatsheet.md @@ -38,6 +38,11 @@ complete -F __start_kubectl k source <(kubectl completion zsh) # setup autocomplete in zsh into the current shell echo "[[ $commands[kubectl] ]] && source <(kubectl completion zsh)" >> ~/.zshrc # add autocomplete permanently to your zsh shell ``` +### A Note on --all-namespaces + +Appending --all-namespaces happens frequently enough where you should be aware of the shorthand for --all-namespaces: + +```kubectl -A``` ## Kubectl context and configuration From 7122a4498ad445a6d34a5eaadac73d2269f9af3f Mon Sep 17 00:00:00 2001 From: Thomas Guettler Date: Tue, 1 Mar 2022 21:31:56 +0100 Subject: [PATCH 004/102] fix busybox image to 1.28 (issues with `nslookup`). Changes where done with these commands: reprec 'image: busybox(?!:)' 'image: busybox:1.28' */docs */examples reprec -- '--image=busybox(?!:)' '--image=busybox:1.28' */docs */examples Related issues: https://github.com/docker-library/busybox/issues/48 https://github.com/kubernetes/kubernetes/issues/66924 --- .../docs/concepts/scheduling-eviction/pod-overhead.md | 2 +- content/en/docs/concepts/storage/ephemeral-volumes.md | 4 ++-- content/en/docs/concepts/storage/volumes.md | 4 ++-- content/en/docs/concepts/workloads/pods/_index.md | 2 +- content/en/docs/reference/kubectl/cheatsheet.md | 10 +++++----- .../tasks/administer-cluster/declare-network-policy.md | 6 +++--- .../debug-application-cluster/debug-running-pod.md | 8 ++++---- .../en/docs/tasks/job/parallel-processing-expansion.md | 2 +- .../horizontal-pod-autoscale-walkthrough.md | 2 +- content/en/docs/tutorials/security/apparmor.md | 2 +- content/en/docs/tutorials/services/source-ip.md | 2 +- .../logging/two-files-counter-pod-agent-sidecar.yaml | 2 +- .../two-files-counter-pod-streaming-sidecar.yaml | 6 +++--- .../examples/admin/logging/two-files-counter-pod.yaml | 2 +- .../en/examples/admin/resource/limit-range-pod-1.yaml | 8 ++++---- .../en/examples/admin/resource/limit-range-pod-2.yaml | 8 ++++---- .../en/examples/admin/resource/limit-range-pod-3.yaml | 2 +- content/en/examples/application/job/cronjob.yaml | 2 +- content/en/examples/application/job/job-tmpl.yaml | 2 +- content/en/examples/debug/counter-pod.yaml | 2 +- content/en/examples/pods/init-containers.yaml | 2 +- content/en/examples/pods/inject/dependent-envars.yaml | 2 +- content/en/examples/pods/security/hello-apparmor.yaml | 2 +- .../en/examples/pods/security/security-context.yaml | 2 +- content/en/examples/pods/share-process-namespace.yaml | 2 +- .../projected-secret-downwardapi-configmap.yaml | 2 +- .../projected-secrets-nondefault-permission-mode.yaml | 2 +- .../pods/storage/projected-service-account-token.yaml | 2 +- content/en/examples/pods/storage/projected.yaml | 2 +- .../examples/service/networking/hostaliases-pod.yaml | 2 +- 30 files changed, 49 insertions(+), 49 deletions(-) diff --git a/content/en/docs/concepts/scheduling-eviction/pod-overhead.md b/content/en/docs/concepts/scheduling-eviction/pod-overhead.md index eebc235084..d5db85dadf 100644 --- a/content/en/docs/concepts/scheduling-eviction/pod-overhead.md +++ b/content/en/docs/concepts/scheduling-eviction/pod-overhead.md @@ -72,7 +72,7 @@ spec: runtimeClassName: kata-fc containers: - name: busybox-ctr - image: busybox + image: busybox:1.28 stdin: true tty: true resources: diff --git a/content/en/docs/concepts/storage/ephemeral-volumes.md b/content/en/docs/concepts/storage/ephemeral-volumes.md index 0ee07c7c99..087cf37c73 100644 --- a/content/en/docs/concepts/storage/ephemeral-volumes.md +++ b/content/en/docs/concepts/storage/ephemeral-volumes.md @@ -107,7 +107,7 @@ metadata: spec: containers: - name: my-frontend - image: busybox + image: busybox:1.28 volumeMounts: - mountPath: "/data" name: my-csi-inline-vol @@ -158,7 +158,7 @@ metadata: spec: containers: - name: my-frontend - image: busybox + image: busybox:1.28 volumeMounts: - mountPath: "/scratch" name: scratch-volume diff --git a/content/en/docs/concepts/storage/volumes.md b/content/en/docs/concepts/storage/volumes.md index 50f7bf62a2..69f3c6c757 100644 --- a/content/en/docs/concepts/storage/volumes.md +++ b/content/en/docs/concepts/storage/volumes.md @@ -251,7 +251,7 @@ metadata: spec: containers: - name: test - image: busybox + image: busybox:1.28 volumeMounts: - name: config-vol mountPath: /etc/config @@ -1128,7 +1128,7 @@ spec: fieldRef: apiVersion: v1 fieldPath: metadata.name - image: busybox + image: busybox:1.28 command: [ "sh", "-c", "while [ true ]; do echo 'Hello'; sleep 10; done | tee -a /logs/hello.txt" ] volumeMounts: - name: workdir1 diff --git a/content/en/docs/concepts/workloads/pods/_index.md b/content/en/docs/concepts/workloads/pods/_index.md index fa91723c5a..3aca6e094b 100644 --- a/content/en/docs/concepts/workloads/pods/_index.md +++ b/content/en/docs/concepts/workloads/pods/_index.md @@ -180,7 +180,7 @@ spec: spec: containers: - name: hello - image: busybox + image: busybox:1.28 command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600'] restartPolicy: OnFailure # The pod template ends here diff --git a/content/en/docs/reference/kubectl/cheatsheet.md b/content/en/docs/reference/kubectl/cheatsheet.md index b3c3536b31..a0bd2eb262 100644 --- a/content/en/docs/reference/kubectl/cheatsheet.md +++ b/content/en/docs/reference/kubectl/cheatsheet.md @@ -96,10 +96,10 @@ kubectl apply -f https://git.io/vPieo # create resource(s) from url kubectl create deployment nginx --image=nginx # start a single instance of nginx # create a Job which prints "Hello World" -kubectl create job hello --image=busybox -- echo "Hello World" +kubectl create job hello --image=busybox:1.28 -- echo "Hello World" # create a CronJob that prints "Hello World" every minute -kubectl create cronjob hello --image=busybox --schedule="*/1 * * * *" -- echo "Hello World" +kubectl create cronjob hello --image=busybox:1.28 --schedule="*/1 * * * *" -- echo "Hello World" kubectl explain pods # get the documentation for pod manifests @@ -112,7 +112,7 @@ metadata: spec: containers: - name: busybox - image: busybox + image: busybox:1.28 args: - sleep - "1000000" @@ -124,7 +124,7 @@ metadata: spec: containers: - name: busybox - image: busybox + image: busybox:1.28 args: - sleep - "1000" @@ -314,7 +314,7 @@ kubectl logs my-pod -c my-container --previous # dump pod container logs (s kubectl logs -f my-pod # stream pod logs (stdout) kubectl logs -f my-pod -c my-container # stream pod container logs (stdout, multi-container case) kubectl logs -f -l name=myLabel --all-containers # stream all pods logs with label name=myLabel (stdout) -kubectl run -i --tty busybox --image=busybox -- sh # Run pod as interactive shell +kubectl run -i --tty busybox --image=busybox:1.28 -- sh # Run pod as interactive shell kubectl run nginx --image=nginx -n mynamespace # Start a single instance of nginx pod in the namespace of mynamespace kubectl run nginx --image=nginx # Run pod nginx and write its spec into a file called pod.yaml --dry-run=client -o yaml > pod.yaml diff --git a/content/en/docs/tasks/administer-cluster/declare-network-policy.md b/content/en/docs/tasks/administer-cluster/declare-network-policy.md index 7acbaa9e7d..ac9715b909 100644 --- a/content/en/docs/tasks/administer-cluster/declare-network-policy.md +++ b/content/en/docs/tasks/administer-cluster/declare-network-policy.md @@ -68,7 +68,7 @@ pod/nginx-701339712-e0qfq 1/1 Running 0 35s You should be able to access the new `nginx` service from other Pods. To access the `nginx` Service from another Pod in the `default` namespace, start a busybox container: ```console -kubectl run busybox --rm -ti --image=busybox -- /bin/sh +kubectl run busybox --rm -ti --image=busybox:1.28 -- /bin/sh ``` In your shell, run the following command: @@ -111,7 +111,7 @@ networkpolicy.networking.k8s.io/access-nginx created When you attempt to access the `nginx` Service from a Pod without the correct labels, the request times out: ```console -kubectl run busybox --rm -ti --image=busybox -- /bin/sh +kubectl run busybox --rm -ti --image=busybox:1.28 -- /bin/sh ``` In your shell, run the command: @@ -130,7 +130,7 @@ wget: download timed out You can create a Pod with the correct labels to see that the request is allowed: ```console -kubectl run busybox --rm -ti --labels="access=true" --image=busybox -- /bin/sh +kubectl run busybox --rm -ti --labels="access=true" --image=busybox:1.28 -- /bin/sh ``` In your shell, run the command: diff --git a/content/en/docs/tasks/debug-application-cluster/debug-running-pod.md b/content/en/docs/tasks/debug-application-cluster/debug-running-pod.md index 9653ff05ef..c3922ed0a1 100644 --- a/content/en/docs/tasks/debug-application-cluster/debug-running-pod.md +++ b/content/en/docs/tasks/debug-application-cluster/debug-running-pod.md @@ -110,7 +110,7 @@ specify the `-i`/`--interactive` argument, `kubectl` will automatically attach to the console of the Ephemeral Container. ```shell -kubectl debug -it ephemeral-demo --image=busybox --target=ephemeral-demo +kubectl debug -it ephemeral-demo --image=busybox:1.28 --target=ephemeral-demo ``` ``` @@ -182,7 +182,7 @@ but you need debugging utilities not included in `busybox`. You can simulate this scenario using `kubectl run`: ```shell -kubectl run myapp --image=busybox --restart=Never -- sleep 1d +kubectl run myapp --image=busybox:1.28 --restart=Never -- sleep 1d ``` Run this command to create a copy of `myapp` named `myapp-debug` that adds a @@ -225,7 +225,7 @@ To simulate a crashing application, use `kubectl run` to create a container that immediately exits: ``` -kubectl run --image=busybox myapp -- false +kubectl run --image=busybox:1.28 myapp -- false ``` You can see using `kubectl describe pod myapp` that this container is crashing: @@ -283,7 +283,7 @@ additional utilities. As an example, create a Pod using `kubectl run`: ``` -kubectl run myapp --image=busybox --restart=Never -- sleep 1d +kubectl run myapp --image=busybox:1.28 --restart=Never -- sleep 1d ``` Now use `kubectl debug` to make a copy and change its container image diff --git a/content/en/docs/tasks/job/parallel-processing-expansion.md b/content/en/docs/tasks/job/parallel-processing-expansion.md index 30942b3ede..f62515fda0 100644 --- a/content/en/docs/tasks/job/parallel-processing-expansion.md +++ b/content/en/docs/tasks/job/parallel-processing-expansion.md @@ -201,7 +201,7 @@ spec: spec: containers: - name: c - image: busybox + image: busybox:1.28 command: ["sh", "-c", "echo Processing URL {{ url }} && sleep 5"] restartPolicy: Never {% endfor %} diff --git a/content/en/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough.md b/content/en/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough.md index 04d3e3daaa..3e66272e48 100644 --- a/content/en/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough.md +++ b/content/en/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough.md @@ -152,7 +152,7 @@ runs in an infinite loop, sending queries to the php-apache service. ```shell # Run this in a separate terminal # so that the load generation continues and you can carry on with the rest of the steps -kubectl run -i --tty load-generator --rm --image=busybox --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done" +kubectl run -i --tty load-generator --rm --image=busybox:1.28 --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done" ``` Now run: diff --git a/content/en/docs/tutorials/security/apparmor.md b/content/en/docs/tutorials/security/apparmor.md index 992841e356..e6e90b6ef4 100644 --- a/content/en/docs/tutorials/security/apparmor.md +++ b/content/en/docs/tutorials/security/apparmor.md @@ -264,7 +264,7 @@ metadata: spec: containers: - name: hello - image: busybox + image: busybox:1.28 command: [ "sh", "-c", "echo 'Hello AppArmor!' && sleep 1h" ] EOF pod/hello-apparmor-2 created diff --git a/content/en/docs/tutorials/services/source-ip.md b/content/en/docs/tutorials/services/source-ip.md index a5b0d5a1d2..bb9a622c98 100644 --- a/content/en/docs/tutorials/services/source-ip.md +++ b/content/en/docs/tutorials/services/source-ip.md @@ -119,7 +119,7 @@ clusterip ClusterIP 10.0.170.92 80/TCP 51s And hitting the `ClusterIP` from a pod in the same cluster: ```shell -kubectl run busybox -it --image=busybox --restart=Never --rm +kubectl run busybox -it --image=busybox:1.28 --restart=Never --rm ``` The output is similar to this: ``` diff --git a/content/en/examples/admin/logging/two-files-counter-pod-agent-sidecar.yaml b/content/en/examples/admin/logging/two-files-counter-pod-agent-sidecar.yaml index b37b616e6f..ddfb8104cb 100644 --- a/content/en/examples/admin/logging/two-files-counter-pod-agent-sidecar.yaml +++ b/content/en/examples/admin/logging/two-files-counter-pod-agent-sidecar.yaml @@ -5,7 +5,7 @@ metadata: spec: containers: - name: count - image: busybox + image: busybox:1.28 args: - /bin/sh - -c diff --git a/content/en/examples/admin/logging/two-files-counter-pod-streaming-sidecar.yaml b/content/en/examples/admin/logging/two-files-counter-pod-streaming-sidecar.yaml index 87bd198cfd..6b7d1f1201 100644 --- a/content/en/examples/admin/logging/two-files-counter-pod-streaming-sidecar.yaml +++ b/content/en/examples/admin/logging/two-files-counter-pod-streaming-sidecar.yaml @@ -5,7 +5,7 @@ metadata: spec: containers: - name: count - image: busybox + image: busybox:1.28 args: - /bin/sh - -c @@ -22,13 +22,13 @@ spec: - name: varlog mountPath: /var/log - name: count-log-1 - image: busybox + image: busybox:1.28 args: [/bin/sh, -c, 'tail -n+1 -f /var/log/1.log'] volumeMounts: - name: varlog mountPath: /var/log - name: count-log-2 - image: busybox + image: busybox:1.28 args: [/bin/sh, -c, 'tail -n+1 -f /var/log/2.log'] volumeMounts: - name: varlog diff --git a/content/en/examples/admin/logging/two-files-counter-pod.yaml b/content/en/examples/admin/logging/two-files-counter-pod.yaml index 6ebeb717a1..31bbed3cf8 100644 --- a/content/en/examples/admin/logging/two-files-counter-pod.yaml +++ b/content/en/examples/admin/logging/two-files-counter-pod.yaml @@ -5,7 +5,7 @@ metadata: spec: containers: - name: count - image: busybox + image: busybox:1.28 args: - /bin/sh - -c diff --git a/content/en/examples/admin/resource/limit-range-pod-1.yaml b/content/en/examples/admin/resource/limit-range-pod-1.yaml index 0457792af9..b9bd20d06a 100644 --- a/content/en/examples/admin/resource/limit-range-pod-1.yaml +++ b/content/en/examples/admin/resource/limit-range-pod-1.yaml @@ -5,7 +5,7 @@ metadata: spec: containers: - name: busybox-cnt01 - image: busybox + image: busybox:1.28 command: ["/bin/sh"] args: ["-c", "while true; do echo hello from cnt01; sleep 10;done"] resources: @@ -16,7 +16,7 @@ spec: memory: "200Mi" cpu: "500m" - name: busybox-cnt02 - image: busybox + image: busybox:1.28 command: ["/bin/sh"] args: ["-c", "while true; do echo hello from cnt02; sleep 10;done"] resources: @@ -24,7 +24,7 @@ spec: memory: "100Mi" cpu: "100m" - name: busybox-cnt03 - image: busybox + image: busybox:1.28 command: ["/bin/sh"] args: ["-c", "while true; do echo hello from cnt03; sleep 10;done"] resources: @@ -32,6 +32,6 @@ spec: memory: "200Mi" cpu: "500m" - name: busybox-cnt04 - image: busybox + image: busybox:1.28 command: ["/bin/sh"] args: ["-c", "while true; do echo hello from cnt04; sleep 10;done"] diff --git a/content/en/examples/admin/resource/limit-range-pod-2.yaml b/content/en/examples/admin/resource/limit-range-pod-2.yaml index efac440269..40da19c1ae 100644 --- a/content/en/examples/admin/resource/limit-range-pod-2.yaml +++ b/content/en/examples/admin/resource/limit-range-pod-2.yaml @@ -5,7 +5,7 @@ metadata: spec: containers: - name: busybox-cnt01 - image: busybox + image: busybox:1.28 command: ["/bin/sh"] args: ["-c", "while true; do echo hello from cnt01; sleep 10;done"] resources: @@ -16,7 +16,7 @@ spec: memory: "200Mi" cpu: "500m" - name: busybox-cnt02 - image: busybox + image: busybox:1.28 command: ["/bin/sh"] args: ["-c", "while true; do echo hello from cnt02; sleep 10;done"] resources: @@ -24,7 +24,7 @@ spec: memory: "100Mi" cpu: "100m" - name: busybox-cnt03 - image: busybox + image: busybox:1.28 command: ["/bin/sh"] args: ["-c", "while true; do echo hello from cnt03; sleep 10;done"] resources: @@ -32,6 +32,6 @@ spec: memory: "200Mi" cpu: "500m" - name: busybox-cnt04 - image: busybox + image: busybox:1.28 command: ["/bin/sh"] args: ["-c", "while true; do echo hello from cnt04; sleep 10;done"] diff --git a/content/en/examples/admin/resource/limit-range-pod-3.yaml b/content/en/examples/admin/resource/limit-range-pod-3.yaml index 8afdb6379c..503200a966 100644 --- a/content/en/examples/admin/resource/limit-range-pod-3.yaml +++ b/content/en/examples/admin/resource/limit-range-pod-3.yaml @@ -5,7 +5,7 @@ metadata: spec: containers: - name: busybox-cnt01 - image: busybox + image: busybox:1.28 resources: limits: memory: "300Mi" diff --git a/content/en/examples/application/job/cronjob.yaml b/content/en/examples/application/job/cronjob.yaml index 9f06ca7bd6..78d0e2d314 100644 --- a/content/en/examples/application/job/cronjob.yaml +++ b/content/en/examples/application/job/cronjob.yaml @@ -10,7 +10,7 @@ spec: spec: containers: - name: hello - image: busybox + image: busybox:1.28 imagePullPolicy: IfNotPresent command: - /bin/sh diff --git a/content/en/examples/application/job/job-tmpl.yaml b/content/en/examples/application/job/job-tmpl.yaml index 790025b38b..d7dbbafd62 100644 --- a/content/en/examples/application/job/job-tmpl.yaml +++ b/content/en/examples/application/job/job-tmpl.yaml @@ -13,6 +13,6 @@ spec: spec: containers: - name: c - image: busybox + image: busybox:1.28 command: ["sh", "-c", "echo Processing item $ITEM && sleep 5"] restartPolicy: Never diff --git a/content/en/examples/debug/counter-pod.yaml b/content/en/examples/debug/counter-pod.yaml index f997886386..a91b2f8915 100644 --- a/content/en/examples/debug/counter-pod.yaml +++ b/content/en/examples/debug/counter-pod.yaml @@ -5,6 +5,6 @@ metadata: spec: containers: - name: count - image: busybox + image: busybox:1.28 args: [/bin/sh, -c, 'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done'] diff --git a/content/en/examples/pods/init-containers.yaml b/content/en/examples/pods/init-containers.yaml index 667b03eccd..e55895d673 100644 --- a/content/en/examples/pods/init-containers.yaml +++ b/content/en/examples/pods/init-containers.yaml @@ -14,7 +14,7 @@ spec: # These containers are run during pod initialization initContainers: - name: install - image: busybox + image: busybox:1.28 command: - wget - "-O" diff --git a/content/en/examples/pods/inject/dependent-envars.yaml b/content/en/examples/pods/inject/dependent-envars.yaml index 2509c6f47b..67d07098ba 100644 --- a/content/en/examples/pods/inject/dependent-envars.yaml +++ b/content/en/examples/pods/inject/dependent-envars.yaml @@ -10,7 +10,7 @@ spec: command: - sh - -c - image: busybox + image: busybox:1.28 env: - name: SERVICE_PORT value: "80" diff --git a/content/en/examples/pods/security/hello-apparmor.yaml b/content/en/examples/pods/security/hello-apparmor.yaml index 3e9b3b2a9c..000645f1c7 100644 --- a/content/en/examples/pods/security/hello-apparmor.yaml +++ b/content/en/examples/pods/security/hello-apparmor.yaml @@ -9,5 +9,5 @@ metadata: spec: containers: - name: hello - image: busybox + image: busybox:1.28 command: [ "sh", "-c", "echo 'Hello AppArmor!' && sleep 1h" ] diff --git a/content/en/examples/pods/security/security-context.yaml b/content/en/examples/pods/security/security-context.yaml index 35cb1eeebe..7903c39c64 100644 --- a/content/en/examples/pods/security/security-context.yaml +++ b/content/en/examples/pods/security/security-context.yaml @@ -12,7 +12,7 @@ spec: emptyDir: {} containers: - name: sec-ctx-demo - image: busybox + image: busybox:1.28 command: [ "sh", "-c", "sleep 1h" ] volumeMounts: - name: sec-ctx-vol diff --git a/content/en/examples/pods/share-process-namespace.yaml b/content/en/examples/pods/share-process-namespace.yaml index af812732a2..bd48bf0ff6 100644 --- a/content/en/examples/pods/share-process-namespace.yaml +++ b/content/en/examples/pods/share-process-namespace.yaml @@ -8,7 +8,7 @@ spec: - name: nginx image: nginx - name: shell - image: busybox + image: busybox:1.28 securityContext: capabilities: add: diff --git a/content/en/examples/pods/storage/projected-secret-downwardapi-configmap.yaml b/content/en/examples/pods/storage/projected-secret-downwardapi-configmap.yaml index 270db99dcd..453dc08c0c 100644 --- a/content/en/examples/pods/storage/projected-secret-downwardapi-configmap.yaml +++ b/content/en/examples/pods/storage/projected-secret-downwardapi-configmap.yaml @@ -5,7 +5,7 @@ metadata: spec: containers: - name: container-test - image: busybox + image: busybox:1.28 volumeMounts: - name: all-in-one mountPath: "/projected-volume" diff --git a/content/en/examples/pods/storage/projected-secrets-nondefault-permission-mode.yaml b/content/en/examples/pods/storage/projected-secrets-nondefault-permission-mode.yaml index f69b43161e..b921fd93c5 100644 --- a/content/en/examples/pods/storage/projected-secrets-nondefault-permission-mode.yaml +++ b/content/en/examples/pods/storage/projected-secrets-nondefault-permission-mode.yaml @@ -5,7 +5,7 @@ metadata: spec: containers: - name: container-test - image: busybox + image: busybox:1.28 volumeMounts: - name: all-in-one mountPath: "/projected-volume" diff --git a/content/en/examples/pods/storage/projected-service-account-token.yaml b/content/en/examples/pods/storage/projected-service-account-token.yaml index 3ad06b5dc7..cc307659a7 100644 --- a/content/en/examples/pods/storage/projected-service-account-token.yaml +++ b/content/en/examples/pods/storage/projected-service-account-token.yaml @@ -5,7 +5,7 @@ metadata: spec: containers: - name: container-test - image: busybox + image: busybox:1.28 volumeMounts: - name: token-vol mountPath: "/service-account" diff --git a/content/en/examples/pods/storage/projected.yaml b/content/en/examples/pods/storage/projected.yaml index 172ca0dee5..4244048eb7 100644 --- a/content/en/examples/pods/storage/projected.yaml +++ b/content/en/examples/pods/storage/projected.yaml @@ -5,7 +5,7 @@ metadata: spec: containers: - name: test-projected-volume - image: busybox + image: busybox:1.28 args: - sleep - "86400" diff --git a/content/en/examples/service/networking/hostaliases-pod.yaml b/content/en/examples/service/networking/hostaliases-pod.yaml index 643813b34a..268bffbbf5 100644 --- a/content/en/examples/service/networking/hostaliases-pod.yaml +++ b/content/en/examples/service/networking/hostaliases-pod.yaml @@ -15,7 +15,7 @@ spec: - "bar.remote" containers: - name: cat-hosts - image: busybox + image: busybox:1.28 command: - cat args: From 6c646319441b63d8bfdf001c767d0f8896daebc9 Mon Sep 17 00:00:00 2001 From: Qiming Teng Date: Mon, 7 Mar 2022 12:37:15 +0800 Subject: [PATCH 005/102] [zh] Optimize k8s extension index page There are some italics font style which doesn't render well in Chinese, we should avoid using them when possible. There are some inappropriate line wraps that are creating extra spaces between Chinese characters, this PR tries to optimizes that as well. The subsection title 'configuration' was not translated, also fixed in this PR. --- .../docs/concepts/extend-kubernetes/_index.md | 104 +++++++++--------- 1 file changed, 53 insertions(+), 51 deletions(-) diff --git a/content/zh/docs/concepts/extend-kubernetes/_index.md b/content/zh/docs/concepts/extend-kubernetes/_index.md index ce5050711f..467388221b 100644 --- a/content/zh/docs/concepts/extend-kubernetes/_index.md +++ b/content/zh/docs/concepts/extend-kubernetes/_index.md @@ -70,16 +70,17 @@ Customization approaches can be broadly divided into *configuration*, which only *Configuration files* and *flags* are documented in the Reference section of the online documentation, under each binary: * [kubelet](/docs/reference/command-line-tools-reference/kubelet/) +* [kube-proxy](/docs/reference/command-line-tools-reference/kube-proxy/) * [kube-apiserver](/docs/reference/command-line-tools-reference/kube-apiserver/) * [kube-controller-manager](/docs/reference/command-line-tools-reference/kube-controller-manager/) * [kube-scheduler](/docs/reference/command-line-tools-reference/kube-scheduler/). --> +## 配置 {#configuration} -## Configuration - -*配置文件*和*参数标志*的说明位于在线文档的参考章节,按可执行文件组织: +配置文件和参数标志的说明位于在线文档的参考章节,按可执行文件组织: * [kubelet](/zh/docs/reference/command-line-tools-reference/kubelet/) +* [kube-proxy](/zh/docs/reference/command-line-tools-reference/kube-proxy/) * [kube-apiserver](/zh/docs/reference/command-line-tools-reference/kube-apiserver/) * [kube-controller-manager](/zh/docs/reference/command-line-tools-reference/kube-controller-manager/) * [kube-scheduler](/zh/docs/reference/command-line-tools-reference/kube-scheduler/). @@ -94,19 +95,19 @@ Flags and configuration files may not always be changeable in a hosted Kubernete 有鉴于此,通常应该在没有其他替代方案时才应考虑更改参数标志和配置文件。 *内置的策略 API*,例如[ResourceQuota](/zh/docs/concepts/policy/resource-quotas/)、 [PodSecurityPolicies](/zh/docs/concepts/policy/pod-security-policy/)、 [NetworkPolicy](/zh/docs/concepts/services-networking/network-policies/) -和基于角色的访问控制([RBAC](/zh/docs/reference/access-authn-authz/rbac/))等等 -都是内置的 Kubernetes API。 +和基于角色的访问控制([RBAC](/zh/docs/reference/access-authn-authz/rbac/)) +等等都是内置的 Kubernetes API。 API 通常用于托管的 Kubernetes 服务和受控的 Kubernetes 安装环境中。 -这些 API 是声明式的,与 Pod 这类其他 Kubernetes 资源遵从相同的约定,所以 -新的集群配置是可复用的,并且可以当作应用程序来管理。 -此外,对于稳定版本的 API 而言,它们与其他 Kubernetes API 一样,采纳的是 -一种[预定义的支持策略](/zh/docs/reference/using-api/deprecation-policy/)。 -出于以上原因,在条件允许的情况下,基于 API 的方案应该优先于*配置文件*和*参数标志*。 +这些 API 是声明式的,与 Pod 这类其他 Kubernetes 资源遵从相同的约定, +所以新的集群配置是可复用的,并且可以当作应用程序来管理。 +此外,对于稳定版本的 API 而言,它们与其他 Kubernetes API 一样, +采纳的是一种[预定义的支持策略](/zh/docs/reference/using-api/deprecation-policy/)。 +出于以上原因,在条件允许的情况下,基于 API 的方案应该优先于配置文件和参数标志。 ## 扩展 {#extensions} @@ -124,7 +125,7 @@ install extensions and fewer will need to author new ones. 它们调整 Kubernetes 的工作方式使之支持新的类型和新的硬件种类。 大多数集群管理员会使用一种托管的 Kubernetes 服务或者其某种发行版本。 -因此,大多数 Kubernetes 用户不需要安装扩展, +这类集群通常都预先安装了扩展。因此,大多数 Kubernetes 用户不需要安装扩展, 至于需要自己编写新的扩展的情况就更少了。 -编写客户端程序有一种特殊的 *Controller(控制器)* 模式,能够与 Kubernetes 很好地 -协同工作。控制器通常会读取某个对象的 `.spec`,或许还会执行一些操作,之后更新 -对象的 `.status`。 -*Controller(控制器)* 是 Kubernetes 的客户端。 +编写客户端程序有一种特殊的 Controller(控制器)模式,能够与 Kubernetes +很好地协同工作。控制器通常会读取某个对象的 `.spec`,或许还会执行一些操作, +之后更新对象的 `.status`。 -当 Kubernetes 充当客户端,调用某远程服务时,对应 -的远程组件称作*Webhook*。 远程服务称作*Webhook 后端*。 +Controller 是 Kubernetes 的客户端。当 Kubernetes 充当客户端, +调用某远程服务时,对应的远程组件称作 *Webhook*,远程服务称作 Webhook 后端。 与控制器模式相似,Webhook 也会在整个架构中引入新的失效点(Point of Failure)。 在 Webhook 模式中,Kubernetes 向远程服务发起网络请求。 -在 *可执行文件插件(Binary Plugin)* 模式中,Kubernetes 执行某个可执行文件(程序)。 -可执行文件插件在 kubelet (例如, -[FlexVolume 插件](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-storage/flexvolume.md) +在 **可执行文件插件(Binary Plugin)** 模式中,Kubernetes +执行某个可执行文件(程序)。可执行文件插件在 kubelet (例如, +[FlexVolume 插件](/zh/docs/concepts/storage/volumes/#flexvolume)) 和[网络插件](/zh/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/)) 和 kubectl 中使用。 @@ -223,12 +222,11 @@ If you are unsure where to start, this flowchart can help. Note that some soluti 2. API 服务器处理所有请求。API 服务器中的几种扩展点能够使用户对请求执行身份认证、 基于其内容阻止请求、编辑请求内容、处理删除操作等等。 - 这些扩展点在 [API 访问扩展](#api-access-extensions) - 节详述。 + 这些扩展点在 [API 访问扩展](#api-access-extensions)节详述。 -3. API 服务器向外提供不同类型的*资源(resources)*。 - *内置的资源类型*,如 `pods`,是由 Kubernetes 项目所定义的,无法改变。 - 你也可以添加自己定义的或者其他项目所定义的称作*自定义资源(Custom Resources)* +3. API 服务器向外提供不同类型的资源(resources)。 + 内置的资源类型,如 `pods`,是由 Kubernetes 项目所定义的,无法改变。 + 你也可以添加自己定义的或者其他项目所定义的称作自定义资源(Custom Resources) 的资源,正如[自定义资源](#user-defined-types)节所描述的那样。 自定义资源通常与 API 访问扩展点结合使用。 @@ -236,12 +234,12 @@ If you are unsure where to start, this flowchart can help. Note that some soluti 有几种方式来扩展调度行为。这些方法将在 [调度器扩展](#scheduler-extensions)节中展开。 -5. Kubernetes 中的很多行为都是通过称为控制器(Controllers)的程序来实现的,这些程序也都是 API 服务器 - 的客户端。控制器常常与自定义资源结合使用。 +5. Kubernetes 中的很多行为都是通过称为控制器(Controllers)的程序来实现的, + 这些程序也都是 API 服务器的客户端。控制器常常与自定义资源结合使用。 6. 组件 kubelet 运行在各个节点上,帮助 Pod 展现为虚拟的服务器并在集群网络中拥有自己的 IP。 - [网络插件](#network-plugins)使得 Kubernetes 能够采用 - 不同实现技术来连接 Pod 网络。 + [网络插件](#network-plugins)使得 Kubernetes 能够采用不同实现技术来连接 + Pod 网络。 7. 组件 kubelet 也会为容器增加或解除存储卷的挂载。 通过[存储插件](#storage-plugins),可以支持新的存储类型。 @@ -320,9 +318,8 @@ Kubernetes has several built-in authentication methods that it supports. It can 这些步骤中都存在扩展点。 -Kubernetes 提供若干内置的身份认证方法。 -它也可以运行在某中身份认证代理的后面,并且可以将来自鉴权头部的令牌发送到 -某个远程服务(Webhook)来执行验证操作。 +Kubernetes 提供若干内置的身份认证方法。它也可以运行在某种身份认证代理的后面, +并且可以将来自鉴权头部的令牌发送到某个远程服务(Webhook)来执行验证操作。 所有这些方法都在[身份认证文档](/zh/docs/reference/access-authn-authz/authentication/) 中有详细论述。 @@ -345,12 +342,12 @@ Kubernetes 提供若干种内置的认证方法,以及 ### 鉴权 {#authorization} -[鉴权](/zh/docs/reference/access-authn-authz/webhook/)操作负责确定特定的用户 -是否可以读、写 API 资源或对其执行其他操作。 +[鉴权](/zh/docs/reference/access-authn-authz/authorization/) +操作负责确定特定的用户是否可以读、写 API 资源或对其执行其他操作。 此操作仅在整个资源集合的层面进行。 换言之,它不会基于对象的特定字段作出不同的判决。 如果内置的鉴权选项无法满足你的需要,你可以使用 @@ -371,10 +368,10 @@ After a request is authorized, if it is a write operation, it also goes through [准入控制](/zh/docs/reference/access-authn-authz/admission-controllers/)处理步骤。 除了内置的处理步骤,还存在一些扩展点: -* [Image Policy webhook](/zh/docs/reference/access-authn-authz/admission-controllers/#imagepolicywebhook) +* [镜像策略 Webhook](/zh/docs/reference/access-authn-authz/admission-controllers/#imagepolicywebhook) 能够限制容器中可以运行哪些镜像。 * 为了执行任意的准入控制,可以使用一种通用的 - [Admission webhook](/zh/docs/reference/access-authn-authz/extensible-admission-controllers/#admission-webhooks) + [准入 Webhook](/zh/docs/reference/access-authn-authz/extensible-admission-controllers/#admission-webhooks) 机制。这类 Webhook 可以拒绝对象创建或更新请求。 +从 Kubernetes v1.23 开始,FlexVolume 被弃用。 +在 Kubernetes 中编写卷驱动的推荐方式是使用树外(Out-of-tree)CSI 驱动。 +详细信息可参阅 [Kubernetes Volume Plugin FAQ for Storage Vendors](https://github.com/kubernetes/community/blob/master/sig-storage/volume-plugin-faq.md#kubernetes-volume-plugin-faq-for-storage-vendors)。 From 461a09332b34e25501303ec7f28fcb14b366cb47 Mon Sep 17 00:00:00 2001 From: Qiming Teng Date: Wed, 9 Mar 2022 21:28:09 +0800 Subject: [PATCH 008/102] [zh] Tune the feature gates page Reformat some line wraps, reorder some items in the description and fix a version missing in table 1. --- .../feature-gates.md | 171 +++++++++++------- 1 file changed, 101 insertions(+), 70 deletions(-) diff --git a/content/en/docs/reference/command-line-tools-reference/feature-gates.md b/content/en/docs/reference/command-line-tools-reference/feature-gates.md index 4e1b4c6184..f33d2d747f 100644 --- a/content/en/docs/reference/command-line-tools-reference/feature-gates.md +++ b/content/en/docs/reference/command-line-tools-reference/feature-gates.md @@ -74,7 +74,7 @@ different Kubernetes components. | `CSIInlineVolume` | `true` | Beta | 1.16 | - | | `CSIMigration` | `false` | Alpha | 1.14 | 1.16 | | `CSIMigration` | `true` | Beta | 1.17 | | -| `CSIMigrationAWS` | `false` | Alpha | 1.14 | | +| `CSIMigrationAWS` | `false` | Alpha | 1.14 | 1.16 | | `CSIMigrationAWS` | `false` | Beta | 1.17 | 1.22 | | `CSIMigrationAWS` | `true` | Beta | 1.23 | | | `CSIMigrationAzureDisk` | `false` | Alpha | 1.15 | 1.18 | @@ -579,39 +579,47 @@ Each feature gate is designed for enabling/disabling a specific feature: See [AppArmor Tutorial](/docs/tutorials/security/apparmor/) for more details. - `AttachVolumeLimit`: Enable volume plugins to report limits on number of volumes that can be attached to a node. - See [dynamic volume limits](/docs/concepts/storage/storage-limits/#dynamic-volume-limits) for more details. -- `BalanceAttachedNodeVolumes`: Include volume count on node to be considered for balanced resource allocation - while scheduling. A node which has closer CPU, memory utilization, and volume count is favored by the scheduler - while making decisions. + See [dynamic volume limits](/docs/concepts/storage/storage-limits/#dynamic-volume-limits) + for more details. +- `BalanceAttachedNodeVolumes`: Include volume count on node to be considered for + balanced resource allocation while scheduling. A node which has closer CPU, + memory utilization, and volume count is favored by the scheduler while making decisions. - `BlockVolume`: Enable the definition and consumption of raw block devices in Pods. See [Raw Block Volume Support](/docs/concepts/storage/persistent-volumes/#raw-block-volume-support) for more details. -- `BoundServiceAccountTokenVolume`: Migrate ServiceAccount volumes to use a projected volume consisting of a - ServiceAccountTokenVolumeProjection. Cluster admins can use metric `serviceaccount_stale_tokens_total` to - monitor workloads that are depending on the extended tokens. If there are no such workloads, turn off - extended tokens by starting `kube-apiserver` with flag `--service-account-extend-token-expiration=false`. +- `BoundServiceAccountTokenVolume`: Migrate ServiceAccount volumes to use a projected volume + consisting of a ServiceAccountTokenVolumeProjection. Cluster admins can use metric + `serviceaccount_stale_tokens_total` to monitor workloads that are depending on the extended + tokens. If there are no such workloads, turn off extended tokens by starting `kube-apiserver` with + flag `--service-account-extend-token-expiration=false`. Check [Bound Service Account Tokens](https://github.com/kubernetes/enhancements/blob/master/keps/sig-auth/1205-bound-service-account-tokens/README.md) - for more details. + for more details. - `ControllerManagerLeaderMigration`: Enables Leader Migration for [kube-controller-manager](/docs/tasks/administer-cluster/controller-manager-leader-migration/#initial-leader-migration-configuration) and - [cloud-controller-manager](/docs/tasks/administer-cluster/controller-manager-leader-migration/#deploy-cloud-controller-manager) which allows a cluster operator to live migrate + [cloud-controller-manager](/docs/tasks/administer-cluster/controller-manager-leader-migration/#deploy-cloud-controller-manager) + which allows a cluster operator to live migrate controllers from the kube-controller-manager into an external controller-manager (e.g. the cloud-controller-manager) in an HA cluster without downtime. - `CPUManager`: Enable container level CPU affinity support, see [CPU Management Policies](/docs/tasks/administer-cluster/cpu-management-policies/). -- `CPUManagerPolicyAlphaOptions`: This allows fine-tuning of CPUManager policies, experimental, Alpha-quality options +- `CPUManagerPolicyAlphaOptions`: This allows fine-tuning of CPUManager policies, + experimental, Alpha-quality options This feature gate guards *a group* of CPUManager options whose quality level is alpha. This feature gate will never graduate to beta or stable. -- `CPUManagerPolicyBetaOptions`: This allows fine-tuning of CPUManager policies, experimental, Beta-quality options +- `CPUManagerPolicyBetaOptions`: This allows fine-tuning of CPUManager policies, + experimental, Beta-quality options This feature gate guards *a group* of CPUManager options whose quality level is beta. This feature gate will never graduate to stable. - `CPUManagerPolicyOptions`: Allow fine-tuning of CPUManager policies. -- `CRIContainerLogRotation`: Enable container log rotation for CRI container runtime. The default max size of a log file is 10MB and the - default max number of log files allowed for a container is 5. These values can be configured in the kubelet config. - See the [logging at node level](/docs/concepts/cluster-administration/logging/#logging-at-the-node-level) documentation for more details. +- `CRIContainerLogRotation`: Enable container log rotation for CRI container runtime. + The default max size of a log file is 10MB and the default max number of + log files allowed for a container is 5. + These values can be configured in the kubelet config. + See [logging at node level](/docs/concepts/cluster-administration/logging/#logging-at-the-node-level) + for more details. - `CSIBlockVolume`: Enable external CSI volume drivers to support block storage. - See the [`csi` raw block volume support](/docs/concepts/storage/volumes/#csi-raw-block-volume-support) - documentation for more details. + See [`csi` raw block volume support](/docs/concepts/storage/volumes/#csi-raw-block-volume-support) + for more details. - `CSIDriverRegistry`: Enable all logic related to the CSIDriver API object in csi.storage.k8s.io. - `CSIInlineVolume`: Enable CSI Inline volumes support for pods. @@ -643,7 +651,8 @@ Each feature gate is designed for enabling/disabling a specific feature: AzureDisk CSI plugin. Requires CSIMigration and CSIMigrationAzureDisk feature flags enabled and AzureDisk CSI plugin installed and configured on all nodes in the cluster. This flag has been deprecated in favor of the - `InTreePluginAzureDiskUnregister` feature flag which prevents the registration of in-tree AzureDisk plugin. + `InTreePluginAzureDiskUnregister` feature flag which prevents the registration + of in-tree AzureDisk plugin. - `CSIMigrationAzureFile`: Enables shims and translation logic to route volume operations from the Azure-File in-tree plugin to AzureFile CSI plugin. Supports falling back to in-tree AzureFile plugin for mount operations to @@ -666,19 +675,13 @@ Each feature gate is designed for enabling/disabling a specific feature: Does not support falling back for provision operations, for those the CSI plugin must be installed and configured. Requires CSIMigration feature flag enabled. -- `csiMigrationRBD`: Enables shims and translation logic to route volume - operations from the RBD in-tree plugin to Ceph RBD CSI plugin. Requires - CSIMigration and csiMigrationRBD feature flags enabled and Ceph CSI plugin - installed and configured in the cluster. This flag has been deprecated in - favor of the - `InTreePluginRBDUnregister` feature flag which prevents the registration of - in-tree RBD plugin. - `CSIMigrationGCEComplete`: Stops registering the GCE-PD in-tree plugin in kubelet and volume controllers and enables shims and translation logic to route volume operations from the GCE-PD in-tree plugin to PD CSI plugin. Requires CSIMigration and CSIMigrationGCE feature flags enabled and PD CSI plugin installed and configured on all nodes in the cluster. This flag has - been deprecated in favor of the `InTreePluginGCEUnregister` feature flag which prevents the registration of in-tree GCE PD plugin. + been deprecated in favor of the `InTreePluginGCEUnregister` feature flag which + prevents the registration of in-tree GCE PD plugin. - `CSIMigrationOpenStack`: Enables shims and translation logic to route volume operations from the Cinder in-tree plugin to Cinder CSI plugin. Supports falling back to in-tree Cinder plugin for mount operations to nodes that have @@ -691,7 +694,14 @@ Each feature gate is designed for enabling/disabling a specific feature: volume operations from the Cinder in-tree plugin to Cinder CSI plugin. Requires CSIMigration and CSIMigrationOpenStack feature flags enabled and Cinder CSI plugin installed and configured on all nodes in the cluster. This flag has - been deprecated in favor of the `InTreePluginOpenStackUnregister` feature flag which prevents the registration of in-tree openstack cinder plugin. + been deprecated in favor of the `InTreePluginOpenStackUnregister` feature flag + which prevents the registration of in-tree openstack cinder plugin. +- `csiMigrationRBD`: Enables shims and translation logic to route volume + operations from the RBD in-tree plugin to Ceph RBD CSI plugin. Requires + CSIMigration and csiMigrationRBD feature flags enabled and Ceph CSI plugin + installed and configured in the cluster. This flag has been deprecated in + favor of the `InTreePluginRBDUnregister` feature flag which prevents the registration of + in-tree RBD plugin. - `CSIMigrationvSphere`: Enables shims and translation logic to route volume operations from the vSphere in-tree plugin to vSphere CSI plugin. Supports falling back to in-tree vSphere plugin for mount operations to nodes that have the feature @@ -704,11 +714,12 @@ Each feature gate is designed for enabling/disabling a specific feature: from the vSphere in-tree plugin to vSphere CSI plugin. Requires CSIMigration and CSIMigrationvSphere feature flags enabled and vSphere CSI plugin installed and configured on all nodes in the cluster. This flag has been deprecated in favor - of the `InTreePluginvSphereUnregister` feature flag which prevents the registration of in-tree vsphere plugin. + of the `InTreePluginvSphereUnregister` feature flag which prevents the + registration of in-tree vsphere plugin. - `CSIMigrationPortworx`: Enables shims and translation logic to route volume operations from the Portworx in-tree plugin to Portworx CSI plugin. - Requires Portworx CSI driver to be installed and configured in the cluster, and feature gate set `CSIMigrationPortworx=true` in kube-controller-manager and kubelet configs. -- `CSINodeInfo`: Enable all logic related to the CSINodeInfo API object in csi.storage.k8s.io. + Requires Portworx CSI driver to be installed and configured in the cluster. +- `CSINodeInfo`: Enable all logic related to the CSINodeInfo API object in `csi.storage.k8s.io`. - `CSIPersistentVolume`: Enable discovering and mounting volumes provisioned through a [CSI (Container Storage Interface)](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/storage/container-storage-interface.md) compatible volume plugin. @@ -736,7 +747,9 @@ Each feature gate is designed for enabling/disabling a specific feature: version 1 of the same controller is selected. - `CustomCPUCFSQuotaPeriod`: Enable nodes to change `cpuCFSQuotaPeriod` in [kubelet config](/docs/tasks/administer-cluster/kubelet-config-file/). -- `CustomResourceValidationExpressions`: Enable expression language validation in CRD which will validate customer resource based on validation rules written in `x-kubernetes-validations` extension. +- `CustomResourceValidationExpressions`: Enable expression language validation in CRD + which will validate customer resource based on validation rules written in + the `x-kubernetes-validations` extension. - `CustomPodDNS`: Enable customizing the DNS settings for a Pod using its `dnsConfig` property. Check [Pod's DNS Config](/docs/concepts/services-networking/dns-pod-service/#pods-dns-config) for more details. @@ -819,7 +832,8 @@ Each feature gate is designed for enabling/disabling a specific feature: host mounts, or containers that are privileged or using specific non-namespaced capabilities (e.g. `MKNODE`, `SYS_MODULE` etc.). This should only be enabled if user namespace remapping is enabled in the Docker daemon. -- `ExternalPolicyForExternalIP`: Fix a bug where ExternalTrafficPolicy is not applied to Service ExternalIPs. +- `ExternalPolicyForExternalIP`: Fix a bug where ExternalTrafficPolicy is not + applied to Service ExternalIPs. - `GCERegionalPersistentDisk`: Enable the regional PD feature on GCE. - `GenericEphemeralVolume`: Enables ephemeral, inline volumes that support all features of normal volumes (can be provided by third-party storage vendors, storage capacity tracking, @@ -832,8 +846,10 @@ Each feature gate is designed for enabling/disabling a specific feature: for more details. - `GracefulNodeShutdownBasedOnPodPriority`: Enables the kubelet to check Pod priorities when shutting down a node gracefully. -- `GRPCContainerProbe`: Enables the gRPC probe method for {Liveness,Readiness,Startup}Probe. See [Configure Liveness, Readiness and Startup Probes](/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-a-grpc-liveness-probe). -- `HonorPVReclaimPolicy`: Honor persistent volume reclaim policy when it is `Delete` irrespective of PV-PVC deletion ordering. +- `GRPCContainerProbe`: Enables the gRPC probe method for {Liveness,Readiness,Startup}Probe. + See [Configure Liveness, Readiness and Startup Probes](/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-a-grpc-liveness-probe). +- `HonorPVReclaimPolicy`: Honor persistent volume reclaim policy when it is `Delete` + irrespective of PV-PVC deletion ordering. - `HPAContainerMetrics`: Enable the `HorizontalPodAutoscaler` to scale based on metrics from individual containers in target pods. - `HPAScaleToZero`: Enables setting `minReplicas` to 0 for `HorizontalPodAutoscaler` @@ -845,10 +861,19 @@ Each feature gate is designed for enabling/disabling a specific feature: - `HyperVContainer`: Enable [Hyper-V isolation](https://docs.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/hyperv-container) for Windows containers. -- `IdentifyPodOS`: Allows the Pod OS field to be specified. This helps in identifying the OS of the pod - authoritatively during the API server admission time. In Kubernetes {{< skew currentVersion >}}, the allowed values for the `pod.spec.os.name` are `windows` and `linux`. +- `IdentifyPodOS`: Allows the Pod OS field to be specified. This helps in identifying + the OS of the pod authoritatively during the API server admission time. + In Kubernetes {{< skew currentVersion >}}, the allowed values for the `pod.spec.os.name` + are `windows` and `linux`. - `ImmutableEphemeralVolumes`: Allows for marking individual Secrets and ConfigMaps as immutable for better safety and performance. +- `IndexedJob`: Allows the [Job](/docs/concepts/workloads/controllers/job/) + controller to manage Pod completions per completion index. +- `IngressClassNamespacedParams`: Allow namespace-scoped parameters reference in + `IngressClass` resource. This feature adds two fields - `Scope` and `Namespace` + to `IngressClass.spec.parameters`. +- `Initializers`: Allow asynchronous coordination of object creation using the + Initializers admission plugin. - `InTreePluginAWSUnregister`: Stops registering the aws-ebs in-tree plugin in kubelet and volume controllers. - `InTreePluginAzureDiskUnregister`: Stops registering the azuredisk in-tree plugin in kubelet @@ -865,13 +890,6 @@ Each feature gate is designed for enabling/disabling a specific feature: and volume controllers. - `InTreePluginvSphereUnregister`: Stops registering the vSphere in-tree plugin in kubelet and volume controllers. -- `IndexedJob`: Allows the [Job](/docs/concepts/workloads/controllers/job/) - controller to manage Pod completions per completion index. -- `IngressClassNamespacedParams`: Allow namespace-scoped parameters reference in - `IngressClass` resource. This feature adds two fields - `Scope` and `Namespace` - to `IngressClass.spec.parameters`. -- `Initializers`: Allow asynchronous coordination of object creation using the - Initializers admission plugin. - `IPv6DualStack`: Enable [dual stack](/docs/concepts/services-networking/dual-stack/) support for IPv6. - `JobMutableNodeSchedulingDirectives`: Allows updating node scheduling directives in @@ -889,17 +907,21 @@ Each feature gate is designed for enabling/disabling a specific feature: a file specified using a config file. See [setting kubelet parameters via a config file](/docs/tasks/administer-cluster/kubelet-config-file/) for more details. -- `KubeletCredentialProviders`: Enable kubelet exec credential providers for image pull credentials. -- `KubeletInUserNamespace`: Enables support for running kubelet in a {{}}. +- `KubeletCredentialProviders`: Enable kubelet exec credential providers for + image pull credentials. +- `KubeletInUserNamespace`: Enables support for running kubelet in a + {{}}. See [Running Kubernetes Node Components as a Non-root User](/docs/tasks/administer-cluster/kubelet-in-userns/). - `KubeletPluginsWatcher`: Enable probe-based plugin watcher utility to enable kubelet to discover plugins such as [CSI volume drivers](/docs/concepts/storage/volumes/#csi). - `KubeletPodResources`: Enable the kubelet's pod resources gRPC endpoint. See [Support Device Monitoring](https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/606-compute-device-assignment/README.md) for more details. -- `KubeletPodResourcesGetAllocatable`: Enable the kubelet's pod resources `GetAllocatableResources` functionality. - This API augments the [resource allocation reporting](/docs/concepts/extend-kubernetes/compute-storage-net/device-plugins/#monitoring-device-plugin-resources) - with informations about the allocatable resources, enabling clients to properly track the free compute resources on a node. +- `KubeletPodResourcesGetAllocatable`: Enable the kubelet's pod resources + `GetAllocatableResources` functionality. This API augments the + [resource allocation reporting](/docs/concepts/extend-kubernetes/compute-storage-net/device-plugins/#monitoring-device-plugin-resources) + with informations about the allocatable resources, enabling clients to properly + track the free compute resources on a node. - `LegacyNodeRoleBehavior`: When disabled, legacy behavior in service load balancers and node disruption will ignore the `node-role.kubernetes.io/master` label in favor of the feature-specific labels provided by `NodeDisruptionExclusion` and `ServiceNodeExclusion`. @@ -918,18 +940,22 @@ Each feature gate is designed for enabling/disabling a specific feature: based on logarithmic bucketing of pod timestamps. - `MemoryManager`: Allows setting memory affinity for a container based on NUMA topology. -- `MemoryQoS`: Enable memory protection and usage throttle on pod / container using cgroup v2 memory controller. +- `MemoryQoS`: Enable memory protection and usage throttle on pod / container using + cgroup v2 memory controller. - `MixedProtocolLBService`: Enable using different protocols in the same `LoadBalancer` type Service instance. - `MountContainers`: Enable using utility containers on host as the volume mounter. - `MountPropagation`: Enable sharing volume mounted by one container to other containers or pods. For more details, please see [mount propagation](/docs/concepts/storage/volumes/#mount-propagation). -- `NamespaceDefaultLabelName`: Configure the API Server to set an immutable {{< glossary_tooltip text="label" term_id="label" >}} - `kubernetes.io/metadata.name` on all namespaces, containing the namespace name. -- `NetworkPolicyEndPort`: Enable use of the field `endPort` in NetworkPolicy objects, allowing the selection of a port range instead of a single port. +- `NamespaceDefaultLabelName`: Configure the API Server to set an immutable + {{< glossary_tooltip text="label" term_id="label" >}} `kubernetes.io/metadata.name` + on all namespaces, containing the namespace name. +- `NetworkPolicyEndPort`: Enable use of the field `endPort` in NetworkPolicy objects, + allowing the selection of a port range instead of a single port. - `NodeDisruptionExclusion`: Enable use of the Node label `node.kubernetes.io/exclude-disruption` which prevents nodes from being evacuated during zone failures. -- `NodeLease`: Enable the new Lease API to report node heartbeats, which could be used as a node health signal. +- `NodeLease`: Enable the new Lease API to report node heartbeats, which could be used + as a node health signal. - `NodeSwap`: Enable the kubelet to allocate swap memory for Kubernetes workloads on a node. Must be used with `KubeletConfiguration.failSwapOn` set to false. For more details, please see [swap memory](/docs/concepts/architecture/nodes/#swap-memory) @@ -937,23 +963,23 @@ Each feature gate is designed for enabling/disabling a specific feature: - `OpenAPIEnums`: Enables populating "enum" fields of OpenAPI schemas in the spec returned from the API server. - `OpenAPIV3`: Enables the API server to publish OpenAPI v3. -- `PVCProtection`: Enable the prevention of a PersistentVolumeClaim (PVC) from - being deleted when it is still used by any Pod. - `PodDeletionCost`: Enable the [Pod Deletion Cost](/docs/concepts/workloads/controllers/replicaset/#pod-deletion-cost) feature which allows users to influence ReplicaSet downscaling order. - `PersistentLocalVolumes`: Enable the usage of `local` volume type in Pods. Pod affinity has to be specified if requesting a `local` volume. -- `PodAndContainerStatsFromCRI`: Configure the kubelet to gather container and pod stats from the CRI container runtime - rather than gathering them from cAdvisor. +- `PodAndContainerStatsFromCRI`: Configure the kubelet to gather container and + pod stats from the CRI container runtime rather than gathering them from cAdvisor. - `PodDisruptionBudget`: Enable the [PodDisruptionBudget](/docs/tasks/run-application/configure-pdb/) feature. -- `PodAffinityNamespaceSelector`: Enable the [Pod Affinity Namespace Selector](/docs/concepts/scheduling-eviction/assign-pod-node/#namespace-selector) - and [CrossNamespacePodAffinity](/docs/concepts/policy/resource-quotas/#cross-namespace-pod-affinity-quota) quota scope features. +- `PodAffinityNamespaceSelector`: Enable the + [Pod Affinity Namespace Selector](/docs/concepts/scheduling-eviction/assign-pod-node/#namespace-selector) + and [CrossNamespacePodAffinity](/docs/concepts/policy/resource-quotas/#cross-namespace-pod-affinity-quota) + quota scope features. - `PodOverhead`: Enable the [PodOverhead](/docs/concepts/scheduling-eviction/pod-overhead/) feature to account for pod overheads. - `PodPriority`: Enable the descheduling and preemption of Pods based on their [priorities](/docs/concepts/scheduling-eviction/pod-priority-preemption/). - `PodReadinessGates`: Enable the setting of `PodReadinessGate` field for extending - Pod readiness evaluation. See [Pod readiness gate](/docs/concepts/workloads/pods/pod-lifecycle/#pod-readiness-gate) + Pod readiness evaluation. See [Pod readiness gate](/docs/concepts/workloads/pods/pod-lifecycle/#pod-readiness-gate) for more details. - `PodSecurity`: Enables the `PodSecurity` admission plugin. - `PodShareProcessNamespace`: Enable the setting of `shareProcessNamespace` in a Pod for sharing @@ -964,25 +990,27 @@ Each feature gate is designed for enabling/disabling a specific feature: the cluster. - `ProbeTerminationGracePeriod`: Enable [setting probe-level `terminationGracePeriodSeconds`](/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#probe-level-terminationgraceperiodseconds) - on pods. See the [enhancement proposal](https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/2238-liveness-probe-grace-period) for more details. + on pods. See the [enhancement proposal](https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/2238-liveness-probe-grace-period) + for more details. - `ProcMountType`: Enables control over the type proc mounts for containers by setting the `procMount` field of a SecurityContext. - `ProxyTerminatingEndpoints`: Enable the kube-proxy to handle terminating endpoints when `ExternalTrafficPolicy=Local`. +- `PVCProtection`: Enable the prevention of a PersistentVolumeClaim (PVC) from + being deleted when it is still used by any Pod. - `QOSReserved`: Allows resource reservations at the QoS level preventing pods at lower QoS levels from bursting into resources requested at higher QoS levels (memory only for now). - `ReadWriteOncePod`: Enables the usage of `ReadWriteOncePod` PersistentVolume access mode. -- `RecoverVolumeExpansionFailure`: Enables users to edit their PVCs to smaller sizes so as they can recover from previously issued - volume expansion failures. See - [Recovering from Failure when Expanding Volumes](/docs/concepts/storage/persistent-volumes/#recovering-from-failure-when-expanding-volumes) +- `RecoverVolumeExpansionFailure`: Enables users to edit their PVCs to smaller + sizes so as they can recover from previously issued volume expansion failures. + See [Recovering from Failure when Expanding Volumes](/docs/concepts/storage/persistent-volumes/#recovering-from-failure-when-expanding-volumes) for more details. - `RemainingItemCount`: Allow the API servers to show a count of remaining items in the response to a [chunking list request](/docs/reference/using-api/api-concepts/#retrieving-large-results-sets-in-chunks). -- `RemoveSelfLink`: Deprecates and removes `selfLink` from ObjectMeta and - ListMeta. +- `RemoveSelfLink`: Deprecates and removes `selfLink` from ObjectMeta and ListMeta. - `RequestManagement`: Enables managing request concurrency with prioritization and fairness at each API server. Deprecated by `APIPriorityAndFairness` since 1.17. - `ResourceLimitsPriorityFunction`: Enable a scheduler priority function that @@ -997,7 +1025,8 @@ Each feature gate is designed for enabling/disabling a specific feature: [Bound Service Account Tokens](https://github.com/kubernetes/enhancements/blob/master/keps/sig-auth/1205-bound-service-account-tokens/README.md) for more details. - `RotateKubeletClientCertificate`: Enable the rotation of the client TLS certificate on the kubelet. - See [kubelet configuration](/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/#kubelet-configuration) for more details. + See [kubelet configuration](/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/#kubelet-configuration) + for more details. - `RotateKubeletServerCertificate`: Enable the rotation of the server TLS certificate on the kubelet. See [kubelet configuration](/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/#kubelet-configuration) for more details. @@ -1009,7 +1038,8 @@ Each feature gate is designed for enabling/disabling a specific feature: instead of the DaemonSet controller. - `SCTPSupport`: Enables the _SCTP_ `protocol` value in Pod, Service, Endpoints, EndpointSlice, and NetworkPolicy definitions. -- `SeccompDefault`: Enables the use of `RuntimeDefault` as the default seccomp profile for all workloads. +- `SeccompDefault`: Enables the use of `RuntimeDefault` as the default seccomp profile + for all workloads. The seccomp profile is specified in the `securityContext` of a Pod and/or a Container. - `SelectorIndex`: Allows label and field based indexes in API server watch cache to accelerate list operations. @@ -1023,7 +1053,8 @@ Each feature gate is designed for enabling/disabling a specific feature: - `ServiceInternalTrafficPolicy`: Enables the `internalTrafficPolicy` field on Services - `ServiceLBNodePortControl`: Enables the `allocateLoadBalancerNodePorts` field on Services. - `ServiceLoadBalancerClass`: Enables the `loadBalancerClass` field on Services. See - [Specifying class of load balancer implementation](/docs/concepts/services-networking/service/#load-balancer-class) for more details. + [Specifying class of load balancer implementation](/docs/concepts/services-networking/service/#load-balancer-class) + for more details. - `ServiceLoadBalancerFinalizer`: Enable finalizer protection for Service load balancers. - `ServiceNodeExclusion`: Enable the exclusion of nodes from load balancers created by a cloud provider. A node is eligible for exclusion if labelled with From da8b6d730f6a1845484c482e64ac7930603f80af Mon Sep 17 00:00:00 2001 From: Qiming Teng Date: Fri, 11 Mar 2022 19:55:17 +0800 Subject: [PATCH 009/102] [zh] Update coredns page --- .../docs/tasks/administer-cluster/coredns.md | 119 ++++++++---------- 1 file changed, 55 insertions(+), 64 deletions(-) diff --git a/content/zh/docs/tasks/administer-cluster/coredns.md b/content/zh/docs/tasks/administer-cluster/coredns.md index 22ada21026..24773adbb9 100644 --- a/content/zh/docs/tasks/administer-cluster/coredns.md +++ b/content/zh/docs/tasks/administer-cluster/coredns.md @@ -28,8 +28,10 @@ This page describes the CoreDNS upgrade process and how to install CoreDNS inste ## 关于 CoreDNS @@ -37,11 +39,12 @@ Like Kubernetes, the CoreDNS project is hosted by the {{< glossary_tooltip text= 与 Kubernetes 一样,CoreDNS 项目由 {{< glossary_tooltip text="CNCF" term_id="cncf" >}} 托管。 -通过在现有的集群中替换 kube-dns,可以在集群中使用 CoreDNS 代替 kube-dns 部署, -或者使用 kubeadm 等工具来为你部署和升级集群。 +通过替换现有集群部署中的 kube-dns,或者使用 kubeadm 等工具来为你部署和升级集群, +可以在你的集群中使用 CoreDNS 而非 kube-dns, - ## 迁移到 CoreDNS ### 使用 kubeadm 升级现有集群 +在 Kubernetes 1.21 版本中,kubeadm 移除了对将 `kube-dns` 作为 DNS 应用的支持。 +对于 `kubeadm` v{{< skew currentVersion >}},所支持的唯一的集群 DNS 应用是 CoreDNS。 + + -在 Kubernetes 1.10 及更高版本中,当你使用 `kubeadm` 升级使用 `kube-dns` 的集群时,你还可以迁移到 CoreDNS。 -在本例中 `kubeadm` 将生成 CoreDNS 配置("Corefile")基于 `kube-dns` ConfigMap, +当你使用 `kubeadm` 升级使用 `kube-dns` 的集群时,你还可以执行到 CoreDNS 的迁移。 +在这种场景中,`kubeadm` 将基于 `kube-dns` ConfigMap 生成 CoreDNS 配置("Corefile"), 保存存根域和上游名称服务器的配置。 - -如果你正在从 kube-dns 迁移到 CoreDNS,请确保在升级期间将 `CoreDNS` 特性门设置为 `true`。 -例如,`v1.11.0` 升级应该是这样的: - -``` -kubeadm upgrade apply v1.11.0 --feature-gates=CoreDNS=true -``` - - -在 Kubernetes 版本 1.13 和更高版本中,`CoreDNS`特性门已经删除,CoreDNS 在默认情况下使用。 - - -在 1.11 之前的版本中,核心文件将被升级过程中创建的文件覆盖。 -**如果已对其进行自定义,则应保存现有的 ConfigMap。** -在新的 ConfigMap 启动并运行后,你可以重新应用自定义。 - - -如果你在 Kubernetes 1.11 及更高版本中运行 CoreDNS,则在升级期间,将保留现有的 Corefile。 - - -在 kubernetes 1.21 中,kubeadm 移除了对 `kube-dns` 的支持。 - ## 升级 CoreDNS -从 v1.9 起,Kubernetes 提供了 CoreDNS。 -你可以在[此处](https://github.com/coredns/deployment/blob/master/kubernetes/CoreDNS-k8s_version.md) -查看 Kubernetes 随附的 CoreDNS 版本以及对 CoreDNS 所做的更改。 +你可以在 [CoreDNS version in Kubernetes](https://github.com/coredns/deployment/blob/master/kubernetes/CoreDNS-k8s_version.md) +页面查看 kubeadm 为不同版本 Kubernetes 所安装的 CoreDNS 版本。 -如果你只想升级 CoreDNS 或使用自己的自定义镜像,则可以手动升级 CoreDNS。 +如果你只想升级 CoreDNS 或使用自己的定制镜像,也可以手动升级 CoreDNS。 参看[指南和演练](https://github.com/coredns/deployment/blob/master/kubernetes/Upgrading_CoreDNS.md) 文档了解如何平滑升级。 +在升级你的集群过程中,请确保现有 CoreDNS 的配置("Corefile")被保留下来。 + +如果使用 `kubeadm` 工具来升级集群,则 `kubeadm` 可以自动处理保留现有 CoreDNS +配置这一事项。 ## CoreDNS 调优 当资源利用方面有问题时,优化 CoreDNS 的配置可能是有用的。 -有关详细信息,请参阅[有关扩缩 CoreDNS 的文档](https://github.com/coredns/deployment/blob/master/kubernetes/Scaling_CoreDNS.md)。 +有关详细信息,请参阅有关[扩缩 CoreDNS 的文档](https://github.com/coredns/deployment/blob/master/kubernetes/Scaling_CoreDNS.md)。 ## {{% heading "whatsnext" %}} -你可以通过修改 `Corefile` 来配置 [CoreDNS](https://coredns.io),以支持比 kube-dns 更多的用例。 -请参考 [CoreDNS 网站](https://coredns.io/2017/05/08/custom-dns-entries-for-kubernetes/) +你可以通过修改 CoreDNS 的配置("Corefile")来配置 [CoreDNS](https://coredns.io), +以支持比 kube-dns 更多的用例。 +请参考 `kubernetes` CoreDNS 插件的[文档](https://coredns.io/plugins/kubernetes/) +或者 CoreDNS 博客上的博文 +[Custom DNS Entries for Kubernetes](https://coredns.io/2017/05/08/custom-dns-entries-for-kubernetes/), 以了解更多信息。 From 2d0d647d0b60a59e58591e7edd8bbbb0141d6964 Mon Sep 17 00:00:00 2001 From: Qiming Teng Date: Sun, 13 Mar 2022 13:45:28 +0800 Subject: [PATCH 010/102] [zh] Update configure pod configmap This PR resyncs the configure-pod-configmap page, and translates the comments in the reference example YAML files. --- .../configure-pod-configmap.md | 186 +++++++++++------- .../examples/pods/pod-configmap-volume.yaml | 3 +- .../pod-single-configmap-env-variable.yaml | 6 +- 3 files changed, 115 insertions(+), 80 deletions(-) diff --git a/content/zh/docs/tasks/configure-pod-container/configure-pod-configmap.md b/content/zh/docs/tasks/configure-pod-container/configure-pod-configmap.md index da40f40f5e..39c8efac1b 100644 --- a/content/zh/docs/tasks/configure-pod-container/configure-pod-configmap.md +++ b/content/zh/docs/tasks/configure-pod-container/configure-pod-configmap.md @@ -17,8 +17,16 @@ card: +很多应用在其初始化或运行期间要依赖一些配置信息。大多数时候, +存在要调整配置参数所设置的数值的需求。 +ConfigMap 是 Kubernetes 用来向应用 Pod 中注入配置数据的方法。 + ConfigMap 允许你将配置文件与镜像文件分离,以使容器化的应用程序具有可移植性。 本页提供了一系列使用示例,这些示例演示了如何创建 ConfigMap 以及配置 Pod 使用存储在 ConfigMap 中的数据。 @@ -35,8 +43,8 @@ You can use either `kubectl create configmap` or a ConfigMap generator in `kusto --> ## 创建 ConfigMap -你可以使用 `kubectl create configmap` 或者在 `kustomization.yaml` 中的 ConfigMap 生成器 -来创建 ConfigMap。注意,`kubectl` 从 1.14 版本开始支持 `kustomization.yaml`。 +你可以使用 `kubectl create configmap` 或者在 `kustomization.yaml` 中的 ConfigMap +生成器来创建 ConfigMap。注意,`kubectl` 从 1.14 版本开始支持 `kustomization.yaml`。 ### 使用 kubectl create configmap 创建 ConfigMap -你可以使用 `kubectl create configmap` 命令基于 -[目录](#create-configmaps-from-directories)、[文件](#create-configmaps-from-files) -或者[字面值](#create-configmaps-from-literal-values)来创建 ConfigMap: +你可以使用 `kubectl create configmap` +命令基于[目录](#create-configmaps-from-directories)、 +[文件](#create-configmaps-from-files)或者[字面值](#create-configmaps-from-literal-values)来创建 +ConfigMap: ```shell -kubectl create configmap +kubectl create configmap <映射名称> <数据源> ``` -其中,\ 是要设置的 ConfigMap 名称,\ 是要从中提取数据的目录、 +其中,`<映射名称>` 是为 ConfigMap 指定的名称,`<数据源>` 是要从中提取数据的目录、 文件或者字面值。 ConfigMap 对象的名称必须是合法的 [DNS 子域名](/zh/docs/concepts/overview/working-with-objects/names#dns-subdomain-names). @@ -66,8 +75,8 @@ ConfigMap 对象的名称必须是合法的 -在你基于文件来创建 ConfigMap 时,\ 中的键名默认取自 -文件的基本名,而对应的值则默认为文件的内容。 +在你基于文件来创建 ConfigMap 时,`<数据源>` 中的键名默认取自文件的基本名, +而对应的值则默认为文件的内容。 #### 基于目录创建 ConfigMap {#create-configmaps-from-directories} + 你可以使用 `kubectl create configmap` 基于同一目录中的多个文件创建 ConfigMap。 -当你基于目录来创建 ConfigMap 时,kubectl 识别目录下基本名可以作为合法键名的 -文件,并将这些文件打包到新的 ConfigMap 中。普通文件之外的所有目录项都会被 -忽略(例如,子目录、符号链接、设备、管道等等)。 +当你基于目录来创建 ConfigMap 时,kubectl 识别目录下基本名可以作为合法键名的文件, +并将这些文件打包到新的 ConfigMap 中。普通文件之外的所有目录项都会被忽略 +(例如:子目录、符号链接、设备、管道等等)。 例如: @@ -256,7 +266,7 @@ kubectl create configmap game-config-2 --from-file=configure-pod-container/confi -描述上面创建的 `game-config-2` configmap +描述上面创建的 `game-config-2` ConfigMap: ```shell kubectl describe configmaps game-config-2 @@ -324,22 +334,20 @@ enemies=aliens lives=3 allowed="true" --> - -Env 文件包含环境变量列表。 -其中适用以下语法规则: +Env 文件包含环境变量列表。其中适用以下语法规则: - Env 文件中的每一行必须为 VAR=VAL 格式。 - 以#开头的行(即注释)将被忽略。 - 空行将被忽略。 - 引号不会被特殊处理(即它们将成为 ConfigMap 值的一部分)。 -将示例文件下载到 `configure-pod-container/configmap/` 目录 +将示例文件下载到 `configure-pod-container/configmap/` 目录: ```shell wget https://kubernetes.io/examples/configmap/game-env-file.properties -O configure-pod-container/configmap/game-env-file.properties ``` -env 文件 `game-env-file.properties` 如下所示: +Env 文件 `game-env-file.properties` 如下所示: ```shell cat configure-pod-container/configmap/game-env-file.properties @@ -410,10 +418,10 @@ kubectl create configmap config-multi-env-files \ ``` --> ```shell -# 将样本文件下载到 `configure-pod-container/configmap/` 目录 +# 将示例文件下载到 `configure-pod-container/configmap/` 目录 wget https://k8s.io/examples/configmap/ui-env-file.properties -O configure-pod-container/configmap/ui-env-file.properties -# 创建 configmap +# 创建 ConfigMap kubectl create configmap config-multi-env-files \ --from-env-file=configure-pod-container/configmap/game-env-file.properties \ --from-env-file=configure-pod-container/configmap/ui-env-file.properties @@ -432,6 +440,7 @@ kubectl get configmap config-multi-env-files -o yaml where the output is similar to this: --> 输出类似以下内容: + ```yaml apiVersion: v1 kind: ConfigMap @@ -459,13 +468,13 @@ You can define a key other than the file name to use in the `data` section of yo 而不是按默认行为使用文件名: ```shell -kubectl create configmap game-config-3 --from-file== +kubectl create configmap game-config-3 --from-file=<我的键名>=<文件路径> ``` -`` 是你要在 ConfigMap 中使用的键名,`` 是你想要键表示数据源文件的位置。 +`<我的键名>` 是你要在 ConfigMap 中使用的键名,`<文件路径>` 是你想要键所表示的数据源文件的位置。 例如: @@ -479,7 +488,7 @@ would produce the following ConfigMap: --> 将产生以下 ConfigMap: -``` +```shell kubectl get configmaps game-config-3 -o yaml ``` @@ -513,7 +522,9 @@ data: You can use `kubectl create configmap` with the `--from-literal` argument to define a literal value from the command line: --> #### 根据字面值创建 ConfigMap {#create-configmaps-from-literal-values} -你可以将 `kubectl create configmap` 与 `--from-literal` 参数一起使用,从命令行定义文字值: + +你可以将 `kubectl create configmap` 与 `--from-literal` 参数一起使用, +通过命令行定义文字值: ```shell kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm @@ -551,7 +562,6 @@ data: #### 基于文件生成 ConfigMap -例如,要从 `configure-pod-container/configmap/kubectl/game.properties` 文件生成一个 ConfigMap: +例如,要基于 `configure-pod-container/configmap/kubectl/game.properties` +文件生成一个 ConfigMap: ```shell # 创建包含 ConfigMapGenerator 的 kustomization.yaml 文件 @@ -585,11 +596,12 @@ EOF -使用 kustomization 目录创建 ConfigMap 对象: +应用(Apply)kustomization 目录创建 ConfigMap 对象: ```shell kubectl apply -k . ``` + ``` configmap/game-config-4-m9dm2f92bt created ``` @@ -597,7 +609,7 @@ configmap/game-config-4-m9dm2f92bt created -你可以检查 ConfigMap 是这样创建的: +你可以检查 ConfigMap 被创建如下: ```shell kubectl get configmap @@ -645,7 +657,7 @@ with the key `game-special-key` --> #### 定义从文件生成 ConfigMap 时要使用的键 -在 ConfigMap 生成器,你可以定义一个非文件名的键名。 +在 ConfigMap 生成器中,你可以定义一个非文件名的键名。 例如,从 `configure-pod-container/configmap/game.properties` 文件生成 ConfigMap, 但使用 `game-special-key` 作为键名: @@ -662,11 +674,12 @@ EOF -使用 Kustomization 目录创建 ConfigMap 对象。 +应用 Kustomization 目录创建 ConfigMap 对象。 ```shell kubectl apply -k . ``` + ``` configmap/game-config-5-m67dt67794 created ``` @@ -677,7 +690,7 @@ configmap/game-config-5-m67dt67794 created To generate a ConfigMap from literals `special.type=charm` and `special.how=very`, you can specify the ConfigMap generator in `kusotmization.yaml` as --> -#### 从字面值生成 ConfigMap +#### 基于字面值生成 ConfigMap 要基于字符串 `special.type=charm` 和 `special.how=very` 生成 ConfigMap, 可以在 `kusotmization.yaml` 中配置 ConfigMap 生成器: @@ -701,6 +714,7 @@ Apply the kustomization directory to create the ConfigMap object. ```shell kubectl apply -k . ``` + ``` configmap/special-config-2-c92b5mmcf2 created ``` @@ -726,7 +740,7 @@ configmap/special-config-2-c92b5mmcf2 created -2. 将 ConfigMap 中定义的 `special.how` 值分配给 Pod 规范中的 `SPECIAL_LEVEL_KEY` 环境变量。 +2. 将 ConfigMap 中定义的 `special.how` 赋值给 Pod 规约中的 `SPECIAL_LEVEL_KEY` 环境变量。 {{< codenew file="pods/pod-single-configmap-env-variable.yaml" >}} @@ -760,7 +774,7 @@ configmap/special-config-2-c92b5mmcf2 created -* 在 Pod 规范中定义环境变量。 +* 在 Pod 规约中定义环境变量。 {{< codenew file="pods/pod-multiple-configmap-env-variable.yaml" >}} @@ -803,7 +817,8 @@ Kubernetes v1.6 和更高版本支持此功能。 -* 使用 `envFrom` 将所有 ConfigMap 的数据定义为容器环境变量,ConfigMap 中的键成为 Pod 中的环境变量名称。 +* 使用 `envFrom` 将所有 ConfigMap 的数据定义为容器环境变量,ConfigMap + 中的键成为 Pod 中的环境变量名称。 {{< codenew file="pods/pod-configmap-envFrom.yaml" >}} @@ -825,12 +840,13 @@ Kubernetes v1.6 和更高版本支持此功能。 -你可以使用 `$(VAR_NAME)` Kubernetes 替换语法在容器的 `command` 和 `args` 部分中使用 ConfigMap 定义的环境变量。 +你可以使用 `$(VAR_NAME)` Kubernetes 替换语法在容器的 `command` 和 `args` +属性中使用 ConfigMap 定义的环境变量。 -例如,以下 Pod 规范 +例如,以下 Pod 规约 {{< codenew file="pods/pod-configmap-env-var-valueFrom.yaml" >}} @@ -866,7 +882,7 @@ As explained in [Create ConfigMaps from files](#create-configmaps-from-files), w -本节中的示例引用了一个名为 special-config 的 ConfigMap,如下所示: +本节中的示例引用了一个名为 'special-config' 的 ConfigMap,如下所示: {{< codenew file="configmap/configmap-multikeys.yaml" >}} @@ -886,10 +902,11 @@ Add the ConfigMap name under the `volumes` section of the Pod specification. This adds the ConfigMap data to the directory specified as `volumeMounts.mountPath` (in this case, `/etc/config`). The `command` section references the `special.level` item stored in the ConfigMap. --> -### 使用存储在 ConfigMap 中的数据填充数据卷 +### 使用存储在 ConfigMap 中的数据填充卷 在 Pod 规约的 `volumes` 部分下添加 ConfigMap 名称。 -这会将 ConfigMap 数据添加到指定为 `volumeMounts.mountPath` 的目录(在本例中为 `/etc/config`)。 +这会将 ConfigMap 数据添加到 `volumeMounts.mountPath` 所指定的目录 +(在本例中为 `/etc/config`)。 `command` 部分引用存储在 ConfigMap 中的 `special.level`。 {{< codenew file="pods/pod-configmap-volume.yaml" >}} @@ -914,14 +931,14 @@ SPECIAL_TYPE If there are some files in the `/etc/config/` directory, they will be deleted. --> {{< caution >}} -如果在 `/etc/config/` 目录中有一些文件,它们将被删除。 +如果在 `/etc/config/` 目录中有一些文件,这些文件将被删除。 {{< /caution >}} {{< note >}} -文本数据会使用 UTF-8 字符编码的形式展现为文件。如果使用其他字符编码, +文本数据会展现为 UTF-8 字符编码的文件。如果使用其他字符编码, 可以使用 `binaryData`。 {{< /note >}} @@ -931,10 +948,11 @@ Text data is exposed as files using the UTF-8 character encoding. To use some ot Use the `path` field to specify the desired file path for specific ConfigMap items. In this case, the `SPECIAL_LEVEL` item will be mounted in the `config-volume` volume at `/etc/config/keys`. --> -### 将 ConfigMap 数据添加到数据卷中的特定路径 +### 将 ConfigMap 数据添加到卷中的特定路径 使用 `path` 字段为特定的 ConfigMap 项目指定预期的文件路径。 -在这里,ConfigMap中,键值 `SPECIAL_LEVEL` 的内容将挂载在 `config-volume` 数据卷中 `/etc/config/keys` 文件下。 +在这里,ConfigMap 中键 `SPECIAL_LEVEL` 的内容将挂载在 `config-volume` +卷中 `/etc/config/keys` 文件中。 {{< codenew file="pods/pod-configmap-volume-specific-key.yaml" >}} @@ -950,11 +968,12 @@ kubectl create -f https://kubernetes.io/examples/pods/pod-configmap-volume-speci -当 pod 运行时,命令 `cat /etc/config/keys` 产生以下输出: +当 Pod 运行时,命令 `cat /etc/config/keys` 产生以下输出: ``` very ``` + @@ -968,33 +987,49 @@ Like before, all previous files in the `/etc/config/` directory will be deleted. You can project keys to specific paths and specific permissions on a per-file basis. The [Secrets](/docs/concepts/configuration/secret/#using-secrets-as-files-from-a-pod) user guide explains the syntax. --> -### 映射键以指定路径和文件权限 +### 映射键到指定路径并设置文件访问权限 -你可以通过指定键名到特定目录的投射关系,也可以逐个文件地设定访问权限。 +你可以将指定键名投射到特定目录,也可以逐个文件地设定访问权限。 [Secret 用户指南](/zh/docs/concepts/configuration/secret/#using-secrets-as-files-from-a-pod) -中对这一语法提供了解释。 +中为这一语法提供了解释。 + + +### 可选的引用 {#optional-references} + +ConfigMap 引用可以被标记为 “optional(可选的)”。如果所引用的 ConfigMap 不存在, +则所挂载的卷将会是空的。如果所引用的 ConfigMap 确实存在,但是所引用的主键不存在, +则在挂载点下对应的路径也会不存在。 -### 挂载的 ConfigMap 将自动更新 +### 挂载的 ConfigMap 将自动更新 {#mounted-configmaps-are-updated-automatically} -更新已经在数据卷中使用的 ConfigMap 时,已映射的键最终也会被更新。 -`kubelet` 在每次定期同步时都会检查已挂载的 ConfigMap 是否是最新的。 +当某个已被挂载的 ConfigMap 被更新,所投射的内容最终也会被更新。 +对于 Pod 已经启动之后所引用的、可选的 ConfigMap 才出现的情形, +这一动态更新现象也是适用的。 + + +`kubelet` 在每次周期性同步时都会检查已挂载的 ConfigMap 是否是最新的。 但是,它使用其本地的基于 TTL 的缓存来获取 ConfigMap 的当前值。 因此,从更新 ConfigMap 到将新键映射到 Pod 的总延迟可能与 -kubelet 同步周期 + ConfigMap 在 kubelet 中缓存的 TTL 一样长。 +kubelet 同步周期(默认 1 分钟) + ConfigMap 在 kubelet 中缓存的 TTL +(默认 1 分钟)一样长。 +你可以通过更新 Pod 的某个注解来触发立即更新。 {{< note >}} ConfigMap 应该引用属性文件,而不是替换它们。可以将 ConfigMap 理解为类似于 Linux -`/etc` 目录及其内容的东西。例如,如果你从 ConfigMap 创建 +`/etc` 目录及其内容的东西。例如,如果你基于 ConfigMap 创建 [Kubernetes 卷](/zh/docs/concepts/storage/volumes/),则 ConfigMap -中的每个数据项都由该数据卷中的单个文件表示。 +中的每个数据项都由该数据卷中的某个独立的文件表示。 {{< /note >}} -### 限制 +### 限制 {#restrictions} -- 在 Pod 规范中引用之前,必须先创建一个 ConfigMap(除非将 ConfigMap 标记为"可选")。 - 如果引用的 ConfigMap 不存在,则 Pod 将不会启动。同样,引用 ConfigMap 中不存在的键也会阻止 Pod 启动。 +- 在 Pod 规约中引用某个 ConfigMap 之前,必须先创建它(除非将 ConfigMap 标记为 + “optional(可选)”)。如果引用的 ConfigMap 不存在,则 Pod 将不会启动。 + 同样,引用 ConfigMap 中不存在的主键也会令 Pod 无法启动。 -- 如果你使用 `envFrom` 基于 ConfigMap 定义环境变量,那么无效的键将被忽略。 - 可以启动 Pod,但无效名称将记录在事件日志中(`InvalidVariableNames`)。 - 日志消息列出了每个跳过的键。例如: +- 如果你使用 `envFrom` 来基于 ConfigMap 定义环境变量,那么无效的键将被忽略。 + Pod 可以被启动,但无效名称将被记录在事件日志中(`InvalidVariableNames`)。 + 日志消息列出了每个被跳过的键。例如: ```shell kubectl get events @@ -1086,13 +1122,13 @@ data: -- ConfigMap 位于特定的{{< glossary_tooltip term_id="namespace" text="名字空间" >}} - 中。每个 ConfigMap 只能被同一名字空间中的 Pod 引用. +- ConfigMap 位于确定的{{< glossary_tooltip term_id="namespace" text="名字空间" >}}中。 + 每个 ConfigMap 只能被同一名字空间中的 Pod 引用. -- 你不能将 ConfigMap 用于 {{< glossary_tooltip text="静态 Pod" term_id="static-pod" >}}, +- 你不能将 ConfigMap 用于{{< glossary_tooltip text="静态 Pod" term_id="static-pod" >}}, 因为 Kubernetes 不支持这种用法。 ## {{% heading "whatsnext" %}} @@ -1101,5 +1137,5 @@ data: * Follow a real world example of [Configuring Redis using a ConfigMap](/docs/tutorials/configuration/configure-redis-using-configmap/). --> * 浏览[使用 ConfigMap 配置 Redis](/zh/docs/tutorials/configuration/configure-redis-using-configmap/) - 真实实例 + 真实实例。 diff --git a/content/zh/examples/pods/pod-configmap-volume.yaml b/content/zh/examples/pods/pod-configmap-volume.yaml index 23b0f7718e..5203d4c66b 100644 --- a/content/zh/examples/pods/pod-configmap-volume.yaml +++ b/content/zh/examples/pods/pod-configmap-volume.yaml @@ -13,7 +13,6 @@ spec: volumes: - name: config-volume configMap: - # Provide the name of the ConfigMap containing the files you want - # to add to the container + # 提供包含要添加到容器中的文件的 ConfigMap 的名称 name: special-config restartPolicy: Never diff --git a/content/zh/examples/pods/pod-single-configmap-env-variable.yaml b/content/zh/examples/pods/pod-single-configmap-env-variable.yaml index c86123afd7..5777c814f9 100644 --- a/content/zh/examples/pods/pod-single-configmap-env-variable.yaml +++ b/content/zh/examples/pods/pod-single-configmap-env-variable.yaml @@ -8,12 +8,12 @@ spec: image: k8s.gcr.io/busybox command: [ "/bin/sh", "-c", "env" ] env: - # Define the environment variable + # 定义环境变量 - name: SPECIAL_LEVEL_KEY valueFrom: configMapKeyRef: - # The ConfigMap containing the value you want to assign to SPECIAL_LEVEL_KEY + # ConfigMap 包含你要赋给 SPECIAL_LEVEL_KEY 的值 name: special-config - # Specify the key associated with the value + # 指定与取值相关的键名 key: special.how restartPolicy: Never From 0ffcc6612040c3b4f55efe32de8e2c5759e6be4c Mon Sep 17 00:00:00 2001 From: edithturn Date: Sun, 20 Mar 2022 20:33:55 -0500 Subject: [PATCH 011/102] add storage limits documentation --- .../docs/concepts/storage/storage-limits.md | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 content/es/docs/concepts/storage/storage-limits.md diff --git a/content/es/docs/concepts/storage/storage-limits.md b/content/es/docs/concepts/storage/storage-limits.md new file mode 100644 index 0000000000..8654748da0 --- /dev/null +++ b/content/es/docs/concepts/storage/storage-limits.md @@ -0,0 +1,67 @@ +--- +reviewers: +- edithturn +- raelga +- electrocucaracha +title: Límites de volumen específicos del nodo +content_type: concept +--- + + + +Esta página describe la cantidad máxima de Volúmenes que se pueden adjuntar a un nodo para varios proveedores de nube. + +Los proveedores de la nube como Google, Amazon y Microsoft suelen tener un límite en la cantidad de Volúmenes que se pueden adjuntar a un Nodo. Es importante que Kubernetes respete esos límites. De lo contrario, los pods planificados en un Nodo podrían quedarse atascados esperando que se conecten los volúmenes. + + + + + +## Límites predeterminados de Kubernetes + +El Planificador de Kubernetes tiene límites predeterminados en la cantidad de volúmenes que se pueden adjuntar a un Nodo: + + + + + + +
Servicio de almacenamiento en la nubeVolúmenes máximos por Nodo
Amazon Elastic Block Store (EBS)39
Google Persistent Disk16
Microsoft Azure Disk Storage16
+ +## Límites personalizados + +Puede cambiar estos límites configurando el valor de la variable de entorno KUBE_MAX_PD_VOLS y luego iniciando el Planificador. Los controladores CSI pueden tener un procedimiento diferente, consulte su documentación sobre cómo personalizar sus límites. + +Tenga cuidado si establece un límite superior al límite predeterminado. Consulte la documentación del proveedor de la nube para asegurarse de que los Nodos realmente puedan admitir el límite que establezca. + +El límite se aplica a todo el clúster, por lo que afecta a todos los Nodos. + +## Límites de Volumen dinámico + +{{< feature-state state="stable" for_k8s_version="v1.17" >}} + +Los límites de Volumen dinámico son compatibles con los siguientes tipos de Volumen. + +- Amazon EBS +- Google Persistent Disk +- Azure Disk +- CSI + +Para los Volúmenes administrados por complementos de Volumen en árbol, Kubernetes determina automáticamente el tipo de Nodo y aplica la cantidad máxima adecuada de volúmenes para el Nodo. Por ejemplo: + +* En +Google Compute Engine, +se pueden adjuntar hasta 127 Volúmenes a un Nodo, [según el tipo de Nodo](https://cloud.google.com/compute/docs/disks/#pdnumberlimits). + +* Para los discos de Amazon EBS en los tipos de instancias M5,C5,R5,T3 y Z1D, Kubernetes permite que solo se adjunten 25 Volúmenes a un Nodo. Para otros tipos de instancias en +Amazon Elastic Compute Cloud (EC2), +Kubernetes permite adjuntar 39 Volúmenes a un Nodo. + +* En Azure, se pueden conectar hasta 64 discos a un Nodo, según el tipo de Nodo. Para obtener más detalles, consulte [Sizes for virtual machines in Azure](https://docs.microsoft.com/en-us/azure/virtual-machines/windows/sizes). + +* Si un controlador de almacenamiento CSI anuncia una cantidad máxima de Volúmenes para un Nodo (usando `NodeGetInfo`), the {{< glossary_tooltip text="kube-scheduler" term_id="kube-scheduler" >}} respeta ese límite. +Consulte las especificaciones de [CSI specifications](https://github.com/container-storage-interface/spec/blob/master/spec.md#nodegetinfo) para obtener más información. + +* Para los Volúmenes administrados por complementos en árbol que se han migrado a un controlador CSI, la cantidad máxima de Volúmenes será la que informe el controlador CSI. + + From 131f3b2b46698d81503c1cafbbf46310cfd17af2 Mon Sep 17 00:00:00 2001 From: edithturn Date: Sun, 20 Mar 2022 21:01:32 -0500 Subject: [PATCH 012/102] fix minor typo errors --- content/es/docs/concepts/storage/storage-limits.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/content/es/docs/concepts/storage/storage-limits.md b/content/es/docs/concepts/storage/storage-limits.md index 8654748da0..5bcbfc6b20 100644 --- a/content/es/docs/concepts/storage/storage-limits.md +++ b/content/es/docs/concepts/storage/storage-limits.md @@ -3,15 +3,15 @@ reviewers: - edithturn - raelga - electrocucaracha -title: Límites de volumen específicos del nodo +title: Límites de Volumen específicos del Nodo content_type: concept --- -Esta página describe la cantidad máxima de Volúmenes que se pueden adjuntar a un nodo para varios proveedores de nube. +Esta página describe la cantidad máxima de Volúmenes que se pueden adjuntar a un Nodo para varios proveedores de nube. -Los proveedores de la nube como Google, Amazon y Microsoft suelen tener un límite en la cantidad de Volúmenes que se pueden adjuntar a un Nodo. Es importante que Kubernetes respete esos límites. De lo contrario, los pods planificados en un Nodo podrían quedarse atascados esperando que se conecten los volúmenes. +Los proveedores de la nube como Google, Amazon y Microsoft suelen tener un límite en la cantidad de Volúmenes que se pueden adjuntar a un Nodo. Es importante que Kubernetes respete esos límites. De lo contrario, los pods planificados en un Nodo podrían quedarse atascados esperando que se conecten los Volúmenes. @@ -19,7 +19,7 @@ Los proveedores de la nube como Google, Amazon y Microsoft suelen tener un lími ## Límites predeterminados de Kubernetes -El Planificador de Kubernetes tiene límites predeterminados en la cantidad de volúmenes que se pueden adjuntar a un Nodo: +El Planificador de Kubernetes tiene límites predeterminados en la cantidad de Volúmenes que se pueden adjuntar a un Nodo: @@ -47,7 +47,7 @@ Los límites de Volumen dinámico son compatibles con los siguientes tipos de Vo - Azure Disk - CSI -Para los Volúmenes administrados por complementos de Volumen en árbol, Kubernetes determina automáticamente el tipo de Nodo y aplica la cantidad máxima adecuada de volúmenes para el Nodo. Por ejemplo: +Para los Volúmenes administrados por complementos de Volumen en árbol, Kubernetes determina automáticamente el tipo de Nodo y aplica la cantidad máxima adecuada de Volúmenes para el Nodo. Por ejemplo: * En Google Compute Engine, @@ -59,7 +59,7 @@ Kubernetes permite adjuntar 39 Volúmenes a un Nodo. * En Azure, se pueden conectar hasta 64 discos a un Nodo, según el tipo de Nodo. Para obtener más detalles, consulte [Sizes for virtual machines in Azure](https://docs.microsoft.com/en-us/azure/virtual-machines/windows/sizes). -* Si un controlador de almacenamiento CSI anuncia una cantidad máxima de Volúmenes para un Nodo (usando `NodeGetInfo`), the {{< glossary_tooltip text="kube-scheduler" term_id="kube-scheduler" >}} respeta ese límite. +* Si un controlador de almacenamiento CSI anuncia una cantidad máxima de Volúmenes para un Nodo (usando `NodeGetInfo`), el {{< glossary_tooltip text="kube-scheduler" term_id="kube-scheduler" >}} respeta ese límite. Consulte las especificaciones de [CSI specifications](https://github.com/container-storage-interface/spec/blob/master/spec.md#nodegetinfo) para obtener más información. * Para los Volúmenes administrados por complementos en árbol que se han migrado a un controlador CSI, la cantidad máxima de Volúmenes será la que informe el controlador CSI. From 61849547f2f6a2ade1908165030d43e18d4b454c Mon Sep 17 00:00:00 2001 From: Arhell Date: Tue, 22 Mar 2022 10:38:22 +0200 Subject: [PATCH 013/102] [ja] update audit.md --- content/ja/docs/tasks/debug-application-cluster/audit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/ja/docs/tasks/debug-application-cluster/audit.md b/content/ja/docs/tasks/debug-application-cluster/audit.md index b020b9c0b2..c38014b39e 100644 --- a/content/ja/docs/tasks/debug-application-cluster/audit.md +++ b/content/ja/docs/tasks/debug-application-cluster/audit.md @@ -149,6 +149,7 @@ volumeMounts: 最後に`hostPath`を設定します: ```yaml ... +volumes: - name: audit hostPath: path: /etc/kubernetes/audit-policy.yaml @@ -158,7 +159,6 @@ volumeMounts: hostPath: path: /var/log/audit.log type: FileOrCreate - ``` ### Webhookバックエンド From 49436e3dcbea2ce0fde8e0838bf07b6c4279ae53 Mon Sep 17 00:00:00 2001 From: PriyanshuAhlawat Date: Thu, 24 Mar 2022 17:56:10 +0530 Subject: [PATCH 014/102] Update service.md --- .../concepts/services-networking/service.md | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/content/en/docs/concepts/services-networking/service.md b/content/en/docs/concepts/services-networking/service.md index 0298854137..adfc1b09ee 100644 --- a/content/en/docs/concepts/services-networking/service.md +++ b/content/en/docs/concepts/services-networking/service.md @@ -184,10 +184,10 @@ In the example above, traffic is routed to the single endpoint defined in the YAML: `192.0.2.42:9376` (TCP). {{< note >}} -The Kubernetes API server does not allow proxying to endpoints that are not mapped to -pods. Actions such as `kubectl proxy ` where the service has no -selector will fail due to this constraint. This prevents the Kubernetes API server -from being used as a proxy to endpoints the caller may not be authorized to access. +The Kubernetes API server does not allow proxying to endpoints that are not mapped to +pods. Actions such as `kubectl proxy ` where the service has no +selector will fail due to this constraint. This prevents the Kubernetes API server +from being used as a proxy to endpoints the caller may not be authorized to access. {{< /note >}} An ExternalName Service is a special case of Service that does not have @@ -251,7 +251,7 @@ There are a few reasons for using proxying for Services: Later in this page you can read about various kube-proxy implementations work. Overall, you should note that, when running `kube-proxy`, kernel level rules may be -modified (for example, iptables rules might get created), which won't get cleaned up, +modified (for example, iptables rules might get created), which won't get cleaned up, in some cases until you reboot. Thus, running kube-proxy is something that should only be done by an administrator which understands the consequences of having a low level, privileged network proxying service on a computer. Although the `kube-proxy` @@ -278,6 +278,8 @@ Lastly, the user-space proxy installs iptables rules which capture traffic to the Service's `clusterIP` (which is virtual) and `port`. The rules redirect that traffic to the proxy port which proxies the backend Pod. +{{< note >}} Kube-proxy in userspace mode is deprecated. {{< /note >}} + By default, kube-proxy in userspace mode chooses a backend via a round-robin algorithm. ![Services overview diagram for userspace proxy](/images/docs/services-userspace-overview.svg) @@ -708,13 +710,13 @@ Your cluster must have the `ServiceLoadBalancerClass` [feature gate](/docs/refer other versions of Kubernetes, check the documentation for that release. By default, `spec.loadBalancerClass` is `nil` and a `LoadBalancer` type of Service uses the cloud provider's default load balancer implementation if the cluster is configured with -a cloud provider using the `--cloud-provider` component flag. +a cloud provider using the `--cloud-provider` component flag. If `spec.loadBalancerClass` is specified, it is assumed that a load balancer implementation that matches the specified class is watching for Services. Any default load balancer implementation (for example, the one provided by the cloud provider) will ignore Services that have this field set. `spec.loadBalancerClass` can be set on a Service of type `LoadBalancer` only. -Once set, it cannot be changed. +Once set, it cannot be changed. The value of `spec.loadBalancerClass` must be a label-style identifier, with an optional prefix such as "`internal-vip`" or "`example.com/internal-vip`". Unprefixed names are reserved for end-users. @@ -997,7 +999,7 @@ There are other annotations to manage Classic Elastic Load Balancers that are de service.beta.kubernetes.io/aws-load-balancer-security-groups: "sg-53fae93f" # A list of existing security groups to be configured on the ELB created. Unlike the annotation - # service.beta.kubernetes.io/aws-load-balancer-extra-security-groups, this replaces all other security groups previously assigned to the ELB and also overrides the creation + # service.beta.kubernetes.io/aws-load-balancer-extra-security-groups, this replaces all other security groups previously assigned to the ELB and also overrides the creation # of a uniquely generated security group for this ELB. # The first security group ID on this list is used as a source to permit incoming traffic to target worker nodes (service traffic and health checks). # If multiple ELBs are configured with the same security group ID, only a single permit line will be added to the worker node security groups, that means if you delete any @@ -1007,7 +1009,7 @@ There are other annotations to manage Classic Elastic Load Balancers that are de service.beta.kubernetes.io/aws-load-balancer-extra-security-groups: "sg-53fae93f,sg-42efd82e" # A list of additional security groups to be added to the created ELB, this leaves the uniquely generated security group in place, this ensures that every ELB # has a unique security group ID and a matching permit line to allow traffic to the target worker nodes (service traffic and health checks). - # Security groups defined here can be shared between services. + # Security groups defined here can be shared between services. service.beta.kubernetes.io/aws-load-balancer-target-node-labels: "ingress-gw,gw-name=public-api" # A comma separated list of key-value pairs which are used From 2d69c477827e1590ecfd25b6d0cd9c4be572ce88 Mon Sep 17 00:00:00 2001 From: Brett Wolmarans Date: Thu, 24 Mar 2022 10:29:42 -0700 Subject: [PATCH 015/102] Update content/en/docs/reference/kubectl/cheatsheet.md Co-authored-by: Tim Bannister --- content/en/docs/reference/kubectl/cheatsheet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/reference/kubectl/cheatsheet.md b/content/en/docs/reference/kubectl/cheatsheet.md index cb3aa1f27b..eeee1df93e 100644 --- a/content/en/docs/reference/kubectl/cheatsheet.md +++ b/content/en/docs/reference/kubectl/cheatsheet.md @@ -40,7 +40,7 @@ echo "[[ $commands[kubectl] ]] && source <(kubectl completion zsh)" >> ~/.zshrc ``` ### A Note on --all-namespaces -Appending --all-namespaces happens frequently enough where you should be aware of the shorthand for --all-namespaces: +Appending `--all-namespaces` happens frequently enough where you should be aware of the shorthand for `--all-namespaces`: ```kubectl -A``` From 3980c42945a622bfd5ce05f65a2333de6102030c Mon Sep 17 00:00:00 2001 From: Lukas Hass Date: Thu, 24 Mar 2022 19:58:00 +0100 Subject: [PATCH 016/102] Use cat instead of shell built-in to read checksum --- content/en/docs/tasks/tools/install-kubectl-linux.md | 4 ++-- content/en/docs/tasks/tools/install-kubectl-macos.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/content/en/docs/tasks/tools/install-kubectl-linux.md b/content/en/docs/tasks/tools/install-kubectl-linux.md index 987f3a4116..cf2386dfc7 100644 --- a/content/en/docs/tasks/tools/install-kubectl-linux.md +++ b/content/en/docs/tasks/tools/install-kubectl-linux.md @@ -52,7 +52,7 @@ For example, to download version {{< param "fullversion" >}} on Linux, type: Validate the kubectl binary against the checksum file: ```bash - echo "$( Date: Fri, 25 Mar 2022 13:59:04 +0800 Subject: [PATCH 017/102] Fix the ip-masq-agent page --- .../tasks/administer-cluster/ip-masq-agent.md | 73 ++++++++++--------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/content/en/docs/tasks/administer-cluster/ip-masq-agent.md b/content/en/docs/tasks/administer-cluster/ip-masq-agent.md index 2997508a15..e923345d1a 100644 --- a/content/en/docs/tasks/administer-cluster/ip-masq-agent.md +++ b/content/en/docs/tasks/administer-cluster/ip-masq-agent.md @@ -4,31 +4,27 @@ content_type: task --- -This page shows how to configure and enable the ip-masq-agent. - +This page shows how to configure and enable the `ip-masq-agent`. ## {{% heading "prerequisites" %}} - {{< include "task-tutorial-prereqs.md" >}} {{< version-check >}} - - ## IP Masquerade Agent User Guide -The ip-masq-agent configures iptables rules to hide a pod's IP address behind the cluster node's IP address. This is typically done when sending traffic to destinations outside the cluster's pod [CIDR](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing) range. +The `ip-masq-agent` configures iptables rules to hide a pod's IP address behind the cluster node's IP address. This is typically done when sending traffic to destinations outside the cluster's pod [CIDR](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing) range. ### **Key Terms** -* **NAT (Network Address Translation)** - Is a method of remapping one IP address to another by modifying either the source and/or destination address information in the IP header. Typically performed by a device doing IP routing. -* **Masquerading** - A form of NAT that is typically used to perform a many to one address translation, where multiple source IP addresses are masked behind a single address, which is typically the device doing the IP routing. In Kubernetes this is the Node's IP address. -* **CIDR (Classless Inter-Domain Routing)** - Based on the variable-length subnet masking, allows specifying arbitrary-length prefixes. CIDR introduced a new method of representation for IP addresses, now commonly known as **CIDR notation**, in which an address or routing prefix is written with a suffix indicating the number of bits of the prefix, such as 192.168.2.0/24. -* **Link Local** - A link-local address is a network address that is valid only for communications within the network segment or the broadcast domain that the host is connected to. Link-local addresses for IPv4 are defined in the address block 169.254.0.0/16 in CIDR notation. +* **NAT (Network Address Translation)** + Is a method of remapping one IP address to another by modifying either the source and/or destination address information in the IP header. Typically performed by a device doing IP routing. +* **Masquerading** + A form of NAT that is typically used to perform a many to one address translation, where multiple source IP addresses are masked behind a single address, which is typically the device doing the IP routing. In Kubernetes this is the Node's IP address. +* **CIDR (Classless Inter-Domain Routing)** + Based on the variable-length subnet masking, allows specifying arbitrary-length prefixes. CIDR introduced a new method of representation for IP addresses, now commonly known as **CIDR notation**, in which an address or routing prefix is written with a suffix indicating the number of bits of the prefix, such as 192.168.2.0/24. +* **Link Local** + A link-local address is a network address that is valid only for communications within the network segment or the broadcast domain that the host is connected to. Link-local addresses for IPv4 are defined in the address block 169.254.0.0/16 in CIDR notation. The ip-masq-agent configures iptables rules to handle masquerading node/pod IP addresses when sending traffic to destinations outside the cluster node's IP and the Cluster IP range. This essentially hides pod IP addresses behind the cluster node's IP address. In some environments, traffic to "external" addresses must come from a known machine address. For example, in Google Cloud, any traffic to the internet must come from a VM's IP. When containers are used, as in Google Kubernetes Engine, the Pod IP will be rejected for egress. To avoid this, we must hide the Pod IP behind the VM's own IP address - generally known as "masquerade". By default, the agent is configured to treat the three private IP ranges specified by [RFC 1918](https://tools.ietf.org/html/rfc1918) as non-masquerade [CIDR](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing). These ranges are 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16. The agent will also treat link-local (169.254.0.0/16) as a non-masquerade CIDR by default. The agent is configured to reload its configuration from the location */etc/config/ip-masq-agent* every 60 seconds, which is also configurable. @@ -36,14 +32,20 @@ The ip-masq-agent configures iptables rules to handle masquerading node/pod IP a The agent configuration file must be written in YAML or JSON syntax, and may contain three optional keys: -* **nonMasqueradeCIDRs:** A list of strings in [CIDR](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing) notation that specify the non-masquerade ranges. -* **masqLinkLocal:** A Boolean (true / false) which indicates whether to masquerade traffic to the link local prefix 169.254.0.0/16. False by default. -* **resyncInterval:** A time interval at which the agent attempts to reload config from disk. For example: '30s', where 's' means seconds, 'ms' means milliseconds, etc... +* `nonMasqueradeCIDRs`: A list of strings in + [CIDR](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing) notation that specify the non-masquerade ranges. +* `masqLinkLocal`: A Boolean (true/false) which indicates whether to masquerade traffic to the + link local prefix `169.254.0.0/16`. False by default. +* `resyncInterval`: A time interval at which the agent attempts to reload config from disk. + For example: '30s', where 's' means seconds, 'ms' means milliseconds. Traffic to 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16) ranges will NOT be masqueraded. Any other traffic (assumed to be internet) will be masqueraded. An example of a local destination from a pod could be its Node's IP address as well as another node's address or one of the IP addresses in Cluster's IP range. Any other traffic will be masqueraded by default. The below entries show the default set of rules that are applied by the ip-masq-agent: -``` +```shell iptables -t nat -L IP-MASQ-AGENT +``` + +```none RETURN all -- anywhere 169.254.0.0/16 /* ip-masq-agent: cluster-local traffic should not be subject to MASQUERADE */ ADDRTYPE match dst-type !LOCAL RETURN all -- anywhere 10.0.0.0/8 /* ip-masq-agent: cluster-local traffic should not be subject to MASQUERADE */ ADDRTYPE match dst-type !LOCAL RETURN all -- anywhere 172.16.0.0/12 /* ip-masq-agent: cluster-local traffic should not be subject to MASQUERADE */ ADDRTYPE match dst-type !LOCAL @@ -52,33 +54,35 @@ MASQUERADE all -- anywhere anywhere /* ip-masq-agent: ``` -By default, in GCE/Google Kubernetes Engine starting with Kubernetes version 1.7.0, if network policy is enabled or you are using a cluster CIDR not in the 10.0.0.0/8 range, the ip-masq-agent will run in your cluster. If you are running in another environment, you can add the ip-masq-agent [DaemonSet](/docs/concepts/workloads/controllers/daemonset/) to your cluster: - - +By default, in GCE/Google Kubernetes Engine, if network policy is enabled or +you are using a cluster CIDR not in the 10.0.0.0/8 range, the `ip-masq-agent` +will run in your cluster. If you are running in another environment, +you can add the `ip-masq-agent` [DaemonSet](/docs/concepts/workloads/controllers/daemonset/) +to your cluster. ## Create an ip-masq-agent To create an ip-masq-agent, run the following kubectl command: -` +```shell kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/ip-masq-agent/master/ip-masq-agent.yaml -` +``` You must also apply the appropriate node label to any nodes in your cluster that you want the agent to run on. -` -kubectl label nodes my-node beta.kubernetes.io/masq-agent-ds-ready=true -` +```shell +kubectl label nodes my-node node.kubernetes.io/masq-agent-ds-ready=true +``` More information can be found in the ip-masq-agent documentation [here](https://github.com/kubernetes-sigs/ip-masq-agent) In most cases, the default set of rules should be sufficient; however, if this is not the case for your cluster, you can create and apply a [ConfigMap](/docs/tasks/configure-pod-container/configure-pod-configmap/) to customize the IP ranges that are affected. For example, to allow only 10.0.0.0/8 to be considered by the ip-masq-agent, you can create the following [ConfigMap](/docs/tasks/configure-pod-container/configure-pod-configmap/) in a file called "config". {{< note >}} -It is important that the file is called config since, by default, that will be used as the key for lookup by the ip-masq-agent: +It is important that the file is called config since, by default, that will be used as the key for lookup by the `ip-masq-agent`: -``` +```yaml nonMasqueradeCIDRs: - 10.0.0.0/8 resyncInterval: 60s @@ -87,15 +91,18 @@ resyncInterval: 60s Run the following command to add the config map to your cluster: -``` +```shell kubectl create configmap ip-masq-agent --from-file=config --namespace=kube-system ``` -This will update a file located at */etc/config/ip-masq-agent* which is periodically checked every *resyncInterval* and applied to the cluster node. +This will update a file located at `/etc/config/ip-masq-agent` which is periodically checked every `resyncInterval` and applied to the cluster node. After the resync interval has expired, you should see the iptables rules reflect your changes: -``` +```shell iptables -t nat -L IP-MASQ-AGENT +``` + +```none Chain IP-MASQ-AGENT (1 references) target prot opt source destination RETURN all -- anywhere 169.254.0.0/16 /* ip-masq-agent: cluster-local traffic should not be subject to MASQUERADE */ ADDRTYPE match dst-type !LOCAL @@ -103,9 +110,9 @@ RETURN all -- anywhere 10.0.0.0/8 /* ip-masq-agent: MASQUERADE all -- anywhere anywhere /* ip-masq-agent: outbound traffic should be subject to MASQUERADE (this match must come after cluster-local CIDR matches) */ ADDRTYPE match dst-type !LOCAL ``` -By default, the link local range (169.254.0.0/16) is also handled by the ip-masq agent, which sets up the appropriate iptables rules. To have the ip-masq-agent ignore link local, you can set *masqLinkLocal* to true in the config map. +By default, the link local range (169.254.0.0/16) is also handled by the ip-masq agent, which sets up the appropriate iptables rules. To have the ip-masq-agent ignore link local, you can set `masqLinkLocal` to true in the ConfigMap. -``` +```yaml nonMasqueradeCIDRs: - 10.0.0.0/8 resyncInterval: 60s From cfc613135fe6a8c9c308e0685e20e56a504d06f1 Mon Sep 17 00:00:00 2001 From: Qiming Teng Date: Fri, 25 Mar 2022 14:12:41 +0800 Subject: [PATCH 018/102] Fix feature state for ControllerLeaderMigration The feature has been promoted to Beta in 1.22, according to content/en/docs/tasks/administer-cluster/controller-manager-leader-migration.md and upstream source. --- .../reference/command-line-tools-reference/feature-gates.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/content/en/docs/reference/command-line-tools-reference/feature-gates.md b/content/en/docs/reference/command-line-tools-reference/feature-gates.md index 4e1b4c6184..f35801c4b5 100644 --- a/content/en/docs/reference/command-line-tools-reference/feature-gates.md +++ b/content/en/docs/reference/command-line-tools-reference/feature-gates.md @@ -63,7 +63,8 @@ different Kubernetes components. | `AllowInsecureBackendProxy` | `true` | Beta | 1.17 | | | `AnyVolumeDataSource` | `false` | Alpha | 1.18 | | | `AppArmor` | `true` | Beta | 1.4 | | -| `ControllerManagerLeaderMigration` | `false` | Alpha | 1.21 | | +| `ControllerManagerLeaderMigration` | `false` | Alpha | 1.21 | 1.21 | +| `ControllerManagerLeaderMigration` | `true` | Beta | 1.22 | | | `CPUManager` | `false` | Alpha | 1.8 | 1.9 | | `CPUManager` | `true` | Beta | 1.10 | | | `CPUManagerPolicyAlphaOptions` | `false` | Alpha | 1.23 | | From 58a00cfb36ecce57c4c16e6ab949bd2a1bc29f5e Mon Sep 17 00:00:00 2001 From: Qiming Teng Date: Fri, 25 Mar 2022 18:48:27 +0800 Subject: [PATCH 019/102] Remove duplicated contents for accessing the API server The topic of accessing the API server can be found in two places. This is not good. --- .../access-cluster.md | 31 ++----------------- .../run-application/access-api-from-pod.md | 3 +- 2 files changed, 5 insertions(+), 29 deletions(-) diff --git a/content/en/docs/tasks/access-application-cluster/access-cluster.md b/content/en/docs/tasks/access-application-cluster/access-cluster.md index 8e89e12a59..aae96d3e96 100644 --- a/content/en/docs/tasks/access-application-cluster/access-cluster.md +++ b/content/en/docs/tasks/access-application-cluster/access-cluster.md @@ -205,35 +205,10 @@ See documentation for other libraries for how they authenticate. ## Accessing the API from a Pod When accessing the API from a pod, locating and authenticating -to the apiserver are somewhat different. +to the API server are somewhat different. -The recommended way to locate the apiserver within the pod is with -the `kubernetes.default.svc` DNS name, which resolves to a Service IP which in turn -will be routed to an apiserver. - -The recommended way to authenticate to the apiserver is with a -[service account](/docs/tasks/configure-pod-container/configure-service-account/) credential. By kube-system, a pod -is associated with a service account, and a credential (token) for that -service account is placed into the filesystem tree of each container in that pod, -at `/var/run/secrets/kubernetes.io/serviceaccount/token`. - -If available, a certificate bundle is placed into the filesystem tree of each -container at `/var/run/secrets/kubernetes.io/serviceaccount/ca.crt`, and should be -used to verify the serving certificate of the apiserver. - -Finally, the default namespace to be used for namespaced API operations is placed in a file -at `/var/run/secrets/kubernetes.io/serviceaccount/namespace` in each container. - -From within a pod the recommended ways to connect to API are: - - - Run `kubectl proxy` in a sidecar container in the pod, or as a background - process within the container. This proxies the - Kubernetes API to the localhost interface of the pod, so that other processes - in any container of the pod can access it. - - Use the Go client library, and create a client using the `rest.InClusterConfig()` and `kubernetes.NewForConfig()` functions. - They handle locating and authenticating to the apiserver. [example](https://git.k8s.io/client-go/examples/in-cluster-client-configuration/main.go) - -In each case, the credentials of the pod are used to communicate securely with the apiserver. +Please check [Accessing the API from within a Pod](/docs/tasks/run-application/access-api-from-pod/) +for more details. ## Accessing services running on the cluster diff --git a/content/en/docs/tasks/run-application/access-api-from-pod.md b/content/en/docs/tasks/run-application/access-api-from-pod.md index 9eb2521f7f..d56f624cd5 100644 --- a/content/en/docs/tasks/run-application/access-api-from-pod.md +++ b/content/en/docs/tasks/run-application/access-api-from-pod.md @@ -48,7 +48,8 @@ While running in a Pod, the Kubernetes apiserver is accessible via a Service nam do this automatically. The recommended way to authenticate to the API server is with a -[service account](/docs/tasks/configure-pod-container/configure-service-account/) credential. By default, a Pod +[service account](/docs/tasks/configure-pod-container/configure-service-account/) +credential. By default, a Pod is associated with a service account, and a credential (token) for that service account is placed into the filesystem tree of each container in that Pod, at `/var/run/secrets/kubernetes.io/serviceaccount/token`. From 70574cfdb0ccd647229c92fa1421035d6e54599e Mon Sep 17 00:00:00 2001 From: PriyanshuAhlawat Date: Fri, 25 Mar 2022 16:25:55 +0530 Subject: [PATCH 020/102] Update service.md --- content/en/docs/concepts/services-networking/service.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/content/en/docs/concepts/services-networking/service.md b/content/en/docs/concepts/services-networking/service.md index adfc1b09ee..36f8e1af8f 100644 --- a/content/en/docs/concepts/services-networking/service.md +++ b/content/en/docs/concepts/services-networking/service.md @@ -266,6 +266,7 @@ Note that the kube-proxy starts up in different modes, which are determined by i - The ConfigMap parameters for the kube-proxy cannot all be validated and verified on startup. For example, if your operating system doesn't allow you to run iptables commands, the standard kernel kube-proxy implementation will not work. Likewise, if you have an operating system which doesn't support `netsh`, it will not run in Windows userspace mode. ### User space proxy mode {#proxy-mode-userspace} +{{< feature-state for_k8s_version="v1.23" state="deprecated" >}} In this (legacy) mode, kube-proxy watches the Kubernetes control plane for the addition and removal of Service and Endpoint objects. For each Service it opens a @@ -278,8 +279,6 @@ Lastly, the user-space proxy installs iptables rules which capture traffic to the Service's `clusterIP` (which is virtual) and `port`. The rules redirect that traffic to the proxy port which proxies the backend Pod. -{{< note >}} Kube-proxy in userspace mode is deprecated. {{< /note >}} - By default, kube-proxy in userspace mode chooses a backend via a round-robin algorithm. ![Services overview diagram for userspace proxy](/images/docs/services-userspace-overview.svg) From 8a47855a772bf9cff1603eb27bd085e12f6df0f2 Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Fri, 25 Mar 2022 20:11:13 +0800 Subject: [PATCH 021/102] [zh] Update assign-memory-resource.md Signed-off-by: xin.li --- .../tasks/configure-pod-container/assign-memory-resource.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/zh/docs/tasks/configure-pod-container/assign-memory-resource.md b/content/zh/docs/tasks/configure-pod-container/assign-memory-resource.md index 501090706b..d8a9d37b03 100644 --- a/content/zh/docs/tasks/configure-pod-container/assign-memory-resource.md +++ b/content/zh/docs/tasks/configure-pod-container/assign-memory-resource.md @@ -149,10 +149,10 @@ and a memory limit of 200 MiB. ```yaml ... resources: - limits: - memory: 200Mi requests: memory: 100Mi + limits: + memory: 200Mi ... ``` @@ -263,7 +263,7 @@ The output shows that the Container was killed because it is out of memory (OOM) ```shell lastState: terminated: - containerID: docker://65183c1877aaec2e8427bc95609cc52677a454b56fcb24340dbd22917c23b10f + containerID: 65183c1877aaec2e8427bc95609cc52677a454b56fcb24340dbd22917c23b10f exitCode: 137 finishedAt: 2017-06-20T20:52:19Z reason: OOMKilled From 035f0f493f6e0d97fceb9a4b683aafb9060e7eae Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Fri, 25 Mar 2022 20:33:06 +0800 Subject: [PATCH 022/102] [zh] Update enforce-standards-admission-controller.md Signed-off-by: xin.li --- .../enforce-standards-admission-controller.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/zh/docs/tasks/configure-pod-container/enforce-standards-admission-controller.md b/content/zh/docs/tasks/configure-pod-container/enforce-standards-admission-controller.md index d578c8686f..854205cbd8 100644 --- a/content/zh/docs/tasks/configure-pod-container/enforce-standards-admission-controller.md +++ b/content/zh/docs/tasks/configure-pod-container/enforce-standards-admission-controller.md @@ -68,7 +68,7 @@ plugins: # 要豁免的已认证用户名列表 usernames: [] # 要豁免的运行时类名称列表 - runtimeClassNames: [] + runtimeClasses: [] # 要豁免的名字空间列表 namespaces: [] ``` From fe86ff7ae87b405c36e41b8b9f85b36703b92d7c Mon Sep 17 00:00:00 2001 From: Onur Date: Fri, 25 Mar 2022 16:07:49 +0300 Subject: [PATCH 023/102] Update service.md http-web-service as a name for port is failing as it has more than 15 characters, hence the change to http-web-svc --- .../concepts/services-networking/service.md | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/content/en/docs/concepts/services-networking/service.md b/content/en/docs/concepts/services-networking/service.md index 7fc9cd87ce..af56668579 100644 --- a/content/en/docs/concepts/services-networking/service.md +++ b/content/en/docs/concepts/services-networking/service.md @@ -125,7 +125,7 @@ spec: image: nginx:11.14.2 ports: - containerPort: 80 - name: http-web-service + name: http-web-svc --- apiVersion: v1 @@ -139,7 +139,7 @@ spec: - name: name-of-service-port protocol: TCP port: 80 - targetPort: http-web-service + targetPort: http-web-svc ``` @@ -217,10 +217,10 @@ In the example above, traffic is routed to the single endpoint defined in the YAML: `192.0.2.42:9376` (TCP). {{< note >}} -The Kubernetes API server does not allow proxying to endpoints that are not mapped to -pods. Actions such as `kubectl proxy ` where the service has no -selector will fail due to this constraint. This prevents the Kubernetes API server -from being used as a proxy to endpoints the caller may not be authorized to access. +The Kubernetes API server does not allow proxying to endpoints that are not mapped to +pods. Actions such as `kubectl proxy ` where the service has no +selector will fail due to this constraint. This prevents the Kubernetes API server +from being used as a proxy to endpoints the caller may not be authorized to access. {{< /note >}} An ExternalName Service is a special case of Service that does not have @@ -284,7 +284,7 @@ There are a few reasons for using proxying for Services: Later in this page you can read about various kube-proxy implementations work. Overall, you should note that, when running `kube-proxy`, kernel level rules may be -modified (for example, iptables rules might get created), which won't get cleaned up, +modified (for example, iptables rules might get created), which won't get cleaned up, in some cases until you reboot. Thus, running kube-proxy is something that should only be done by an administrator which understands the consequences of having a low level, privileged network proxying service on a computer. Although the `kube-proxy` @@ -299,7 +299,6 @@ Note that the kube-proxy starts up in different modes, which are determined by i - The ConfigMap parameters for the kube-proxy cannot all be validated and verified on startup. For example, if your operating system doesn't allow you to run iptables commands, the standard kernel kube-proxy implementation will not work. Likewise, if you have an operating system which doesn't support `netsh`, it will not run in Windows userspace mode. ### User space proxy mode {#proxy-mode-userspace} -{{< feature-state for_k8s_version="v1.23" state="deprecated" >}} In this (legacy) mode, kube-proxy watches the Kubernetes control plane for the addition and removal of Service and Endpoint objects. For each Service it opens a @@ -742,13 +741,13 @@ Your cluster must have the `ServiceLoadBalancerClass` [feature gate](/docs/refer other versions of Kubernetes, check the documentation for that release. By default, `spec.loadBalancerClass` is `nil` and a `LoadBalancer` type of Service uses the cloud provider's default load balancer implementation if the cluster is configured with -a cloud provider using the `--cloud-provider` component flag. +a cloud provider using the `--cloud-provider` component flag. If `spec.loadBalancerClass` is specified, it is assumed that a load balancer implementation that matches the specified class is watching for Services. Any default load balancer implementation (for example, the one provided by the cloud provider) will ignore Services that have this field set. `spec.loadBalancerClass` can be set on a Service of type `LoadBalancer` only. -Once set, it cannot be changed. +Once set, it cannot be changed. The value of `spec.loadBalancerClass` must be a label-style identifier, with an optional prefix such as "`internal-vip`" or "`example.com/internal-vip`". Unprefixed names are reserved for end-users. @@ -1031,7 +1030,7 @@ There are other annotations to manage Classic Elastic Load Balancers that are de service.beta.kubernetes.io/aws-load-balancer-security-groups: "sg-53fae93f" # A list of existing security groups to be configured on the ELB created. Unlike the annotation - # service.beta.kubernetes.io/aws-load-balancer-extra-security-groups, this replaces all other security groups previously assigned to the ELB and also overrides the creation + # service.beta.kubernetes.io/aws-load-balancer-extra-security-groups, this replaces all other security groups previously assigned to the ELB and also overrides the creation # of a uniquely generated security group for this ELB. # The first security group ID on this list is used as a source to permit incoming traffic to target worker nodes (service traffic and health checks). # If multiple ELBs are configured with the same security group ID, only a single permit line will be added to the worker node security groups, that means if you delete any @@ -1041,7 +1040,7 @@ There are other annotations to manage Classic Elastic Load Balancers that are de service.beta.kubernetes.io/aws-load-balancer-extra-security-groups: "sg-53fae93f,sg-42efd82e" # A list of additional security groups to be added to the created ELB, this leaves the uniquely generated security group in place, this ensures that every ELB # has a unique security group ID and a matching permit line to allow traffic to the target worker nodes (service traffic and health checks). - # Security groups defined here can be shared between services. + # Security groups defined here can be shared between services. service.beta.kubernetes.io/aws-load-balancer-target-node-labels: "ingress-gw,gw-name=public-api" # A comma separated list of key-value pairs which are used From d5fccd7c46187b011c2dd5887edaba15e893a7d6 Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Fri, 25 Mar 2022 21:28:57 +0800 Subject: [PATCH 024/102] [zh] Update daemonset.md Signed-off-by: xin.li --- content/zh/docs/concepts/workloads/controllers/daemonset.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/zh/docs/concepts/workloads/controllers/daemonset.md b/content/zh/docs/concepts/workloads/controllers/daemonset.md index a1ac51750b..f4ef51936d 100644 --- a/content/zh/docs/concepts/workloads/controllers/daemonset.md +++ b/content/zh/docs/concepts/workloads/controllers/daemonset.md @@ -209,7 +209,7 @@ If you do not specify either, then the DaemonSet controller will create Pods on ### 通过默认调度器调度 {#scheduled-by-default-scheduler} -{{< feature-state state="stable" for-kubernetes-version="1.17" >}} +{{< feature-state for_kubernetes_version="1.17" state="stable" >}} -* [AKS 应用程序网关 Ingress 控制器](https://azure.github.io/application-gateway-kubernetes-ingress/) +* [AKS 应用程序网关 Ingress 控制器](https://docs.microsoft.com/azure/application-gateway/tutorial-ingress-controller-add-on-existing?toc=https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Faks%2Ftoc.json&bc=https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Fbread%2Ftoc.json) 是一个配置 [Azure 应用程序网关](https://docs.microsoft.com/azure/application-gateway/overview) 的 Ingress 控制器。 * [Ambassador](https://www.getambassador.io/) API 网关是一个基于 From bbe16c5e269c5fab9c5b40422767b103821e0b4e Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Fri, 25 Mar 2022 22:43:30 +0800 Subject: [PATCH 026/102] [zh] Update cncf-code-of-conduct/readme Signed-off-by: xin.li --- content/zh/community/static/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/content/zh/community/static/README.md b/content/zh/community/static/README.md index 6d65182dcc..994a778d9a 100644 --- a/content/zh/community/static/README.md +++ b/content/zh/community/static/README.md @@ -1,5 +1,9 @@ +edit them directly, except by replacing them with new versions. +Localization note: you do not need to create localized versions of any of + the files in this directory. +--> 本路径下的文件从其它地方导入。 除了版本更新,不要直接修改。 +本地化说明:你无需为此目录中的任何文件创建本地化版本。 From 5af719eac8167e14acdf056543262544ed449157 Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Fri, 25 Mar 2022 22:57:06 +0800 Subject: [PATCH 027/102] [zh] Update install-kubectl-macos.md Signed-off-by: xin.li --- content/zh/docs/tasks/tools/install-kubectl-macos.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/content/zh/docs/tasks/tools/install-kubectl-macos.md b/content/zh/docs/tasks/tools/install-kubectl-macos.md index 1ac2d77935..63c17c7901 100644 --- a/content/zh/docs/tasks/tools/install-kubectl-macos.md +++ b/content/zh/docs/tasks/tools/install-kubectl-macos.md @@ -178,12 +178,17 @@ The following methods exist for installing kubectl on macOS: 5. 测试一下,确保你安装的是最新的版本: ```bash kubectl version --client ``` + 或者使用下面命令来查看版本的详细信息: + ```cmd + kubectl version --client --output=yaml + ``` ### 问题 {#questions} @@ -71,7 +71,7 @@ and command-line interfaces (CLIs), such as [`kubectl`](/docs/user-guide/kubectl [教程](/zh/docs/tutorials/)部分则提供对现实世界、特定行业或端到端开发场景的更全面的演练。 [参考](/zh/docs/reference/)部分提供了详细的 [Kubernetes API](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/) 文档 -和命令行 (CLI) 接口的文档,例如[`kubectl`](/zh/docs/reference/kubectl/overview/)。 +和命令行 (CLI) 接口的文档,例如[`kubectl`](/zh/docs/reference/kubectl/)。 ### Stack Overflow {#stack-overflow} 社区中的其他人可能已经问过和你类似的问题,也可能能够帮助解决你的问题。 Kubernetes 团队还会监视[带有 Kubernetes 标签的帖子](https://stackoverflow.com/questions/tagged/kubernetes)。 -如果现有的问题对你没有帮助,请[问一个新问题](https://stackoverflow.com/questions/ask?tags=kubernetes)! +如果现有的问题对你没有帮助,在[问一个新问题](https://stackoverflow.com/questions/ask?tags=kubernetes) +之前,**请[确保你的问题是关于 Stack Overflow 的主题](https://stackoverflow.com/help/on-topic) +并且你需要阅读关于[如何提出新问题](https://stackoverflow.com/help/how-to-ask) +的指南。** + + + + + +`import "k8s.io/apimachinery/pkg/apis/meta/v1"` + + + +提供 Patch 是为了给 Kubernetes PATCH 请求正文提供一个具体的名称和类型。 + +
+ + + + + From dd54580d17831010605a7ce8700282e21cf997f5 Mon Sep 17 00:00:00 2001 From: zhangxyjlu <101087623+zhangxyjlu@users.noreply.github.com> Date: Sat, 26 Mar 2022 15:43:20 +0800 Subject: [PATCH 034/102] [zh]Add 2021-12-16-StatefulSet-PVC-Auto-Deletion.md (#32492) * [zh]Add 2021-12-16-StatefulSet-PVC-Auto-Deletion.md * [zh]Add 2021-12-16-StatefulSet-PVC-Auto-Deletion.md * [zh]Add 2021-12-16-StatefulSet-PVC-Auto-Deletion.md * [zh]Add 2021-12-16-StatefulSet-PVC-Auto-Deletion.md --- ...021-12-16-StatefulSet-PVC-Auto-Deletion.md | 208 ++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 content/zh/blog/_posts/2021-12-16-StatefulSet-PVC-Auto-Deletion.md diff --git a/content/zh/blog/_posts/2021-12-16-StatefulSet-PVC-Auto-Deletion.md b/content/zh/blog/_posts/2021-12-16-StatefulSet-PVC-Auto-Deletion.md new file mode 100644 index 0000000000..e5d592c4e6 --- /dev/null +++ b/content/zh/blog/_posts/2021-12-16-StatefulSet-PVC-Auto-Deletion.md @@ -0,0 +1,208 @@ +--- +layout: blog +title: 'Kubernetes 1.23: StatefulSet PVC 自动删除 (alpha)' +date: 2021-12-16 +slug: kubernetes-1-23-statefulset-pvc-auto-deletion +--- + + + +**作者:** Matthew Cary (谷歌) + + +Kubernetes v1.23 为 [StatefulSets](/zh/docs/concepts/workloads/controllers/statefulset/) +引入了一个新的 alpha 级策略,用来控制由 StatefulSet 规约模板生成的 +[PersistentVolumeClaims](/zh/docs/concepts/storage/persistent-volumes/) (PVCs) 的生命周期, +用于当删除 StatefulSet 或减少 StatefulSet 中的 Pods 数量时 PVCs 应该被自动删除的场景。 + + +## 它解决了什么问题? + + +StatefulSet 规约中可以包含 Pod 和 PVC 的模板。当副本先被创建时,如果 PVC 还不存在, +Kubernetes 控制面会为该副本自动创建一个 PVC。在 Kubernetes 1.23 版本之前, +控制面不会删除 StatefulSet 创建的 PVCs——这依赖集群管理员或你需要部署一些额外的适用的自动化工具来处理。 +管理 PVC 的常见模式是通过手动或使用 Helm 等工具,PVC 的具体生命周期由管理它的工具跟踪。 +使用 StatefulSet 时必须自行确定 StatefulSet 创建哪些 PVC,以及它们的生命周期应该是什么。 + + +在这个新特性之前,当一个 StatefulSet 管理的副本消失时,无论是因为 StatefulSet 减少了它的副本数, +还是因为它的 StatefulSet 被删除了,PVC 及其下层的卷仍然存在,需要手动删除。 +当存储数据比较重要时,这样做是合理的,但在许多情况下,这些 PVC 中的持久化数据要么是临时的, +要么可以从另一个源端重建。在这些情况下,删除 StatefulSet 或减少副本后留下的 PVC 及其下层的卷是不必要的, +还会产生成本,需要手动清理。 + + +## 新的 StatefulSet PVC 保留策略 + + +如果你启用这个新 alpha 特性,StatefulSet 规约中就可以包含 PersistentVolumeClaim 的保留策略。 +该策略用于控制是否以及何时删除基于 StatefulSet 的 `volumeClaimTemplate` 属性所创建的 PVCs。 +保留策略的首次迭代包含两种可能删除 PVC 的情况。 + + +第一种情况是 StatefulSet 资源被删除时(这意味着所有副本也被删除),这由 `whenDeleted` 策略控制的。 +第二种情况是 StatefulSet 缩小时,即删除 StatefulSet 部分副本,这由 `whenScaled` 策略控制。 +在这两种情况下,策略即可以是 `Retain` 不涉及相应 PVCs 的改变,也可以是 `Delete` 即删除对应的 PVCs。 +删除是通过普通的[对象删除](/zh/docs/concepts/architecture/garbage-collection/)完成的, +因此,的所有保留策略都会被遵照执行。 + + +该策略形成包含四种情况的矩阵。我将逐一介绍,并为每一种情况给出一个例子。 + + + * **`whenDeleted` 和 `whenScaled` 都是 `Retain`。** 这与 StatefulSets 的现有行为一致, + 即不删除 PVCs。 这也是默认的保留策略。它适用于 StatefulSet + 卷上的数据是不可替代的且只能手动删除的情况。 + + + * **`whenDeleted` 是 `Delete` 但 `whenScaled` 是 `Retain`。** 在这种情况下, + 只有当整个 StatefulSet 被删除时,PVCs 才会被删除。 + 如果减少 StatefulSet 副本,PVCs 不会删除,这意味着如果增加副本时,可以从前一个副本重新连接所有数据。 + 这可能用于临时的 StatefulSet,例如在 CI 实例或 ETL 管道中, + StatefulSet 上的数据仅在 StatefulSet 生命周期内才需要,但在任务运行时数据不易重构。 + 任何保留状态对于所有先缩小后扩大的副本都是必需的。 + + + * **`whenDeleted` 和 `whenScaled` 都是 `Delete`。** 当其副本不再被需要时,PVCs 会立即被删除。 + 注意,这并不包括 Pod 被删除且有新版本被调度的情况,例如当节点被腾空而 Pod 需要迁移到别处时。 + 只有当副本不再被需要时,如按比例缩小或删除 StatefulSet 时,才会删除 PVC。 + 此策略适用于数据生命周期短于副本生命周期的情况。即数据很容易重构, + 且删除未使用的 PVC 所节省的成本比快速增加副本更重要,或者当创建一个新的副本时, + 来自以前副本的任何数据都不可用,必须重新构建。 + + + * **`whenDeleted` 是 `Retain` 但 `whenScaled` 是 `Delete`。** 这与前一种情况类似, + 在增加副本时用保留的 PVCs 快速重构几乎没有什么益处。例如 Elasticsearch 集群就是使用的这种方式。 + 通常,你需要增大或缩小工作负载来满足业务诉求,同时确保最小数量的副本(例如:3)。 + 当减少副本时,数据将从已删除的副本迁移出去,保留这些 PVCs 没有任何用处。 + 但是,这对临时关闭整个 Elasticsearch 集群进行维护时是很有用的。 + 如果需要使 Elasticsearch 系统脱机,可以通过临时删除 StatefulSet 来实现, + 然后通过重新创建 StatefulSet 来恢复 Elasticsearch 集群。 + 保存 Elasticsearch 数据的 PVCs 不会被删除,新的副本将自动使用它们。 + + +查阅[文档](/zh/docs/concepts/workloads/controllers/statefulset/#persistentvolumeclaim-policies) +获取更多详细信息。 + + +## 下一步是什么? + + +启用该功能并尝试一下!在集群上启用 `StatefulSetAutoDeletePVC` 功能,然后使用新策略创建 StatefulSet。 +测试一下,告诉我们你的体验! + + +我很好奇这个属主引用机制在实践中是否有效。例如,我们意识到 Kubernetes 中没有可以知道谁设置了引用的机制, +因此 StatefulSet 控制器可能会与设置自己的引用的自定义控制器发生冲突。 +幸运的是,维护现有的保留行为不涉及任何新属主引用,因此默认行为是兼容的。 + + +请用标签 `sig/apps` 标记你报告的任何问题,并将它们分配给 Matthew Cary +(在 GitHub上 [@mattcary](https://github.com/mattcary))。 + + +尽情体验吧! + From fc144300d658839071e072e93aa019d2ec363cc4 Mon Sep 17 00:00:00 2001 From: Qiming Teng Date: Fri, 25 Feb 2022 23:06:10 +0800 Subject: [PATCH 035/102] [zh] Translate diagram guide --- .../zh/docs/contribute/style/diagram-guide.md | 1262 +++++++++++++++++ 1 file changed, 1262 insertions(+) create mode 100644 content/zh/docs/contribute/style/diagram-guide.md diff --git a/content/zh/docs/contribute/style/diagram-guide.md b/content/zh/docs/contribute/style/diagram-guide.md new file mode 100644 index 0000000000..3f18282756 --- /dev/null +++ b/content/zh/docs/contribute/style/diagram-guide.md @@ -0,0 +1,1262 @@ +--- +title: 图表指南 +linktitle: 图表指南 +content_type: concept +weight: 15 +--- + + + + + +本指南为你展示如何创建、编辑和分享基于 Mermaid Javascript 库的图表。 +Mermaid.js 允许你使用简单的、类似于 Markdown 的语法来在 Markdown 文件中生成图表。 +你也可以使用 Mermaid 来创建 `.svg` 或 `.png` 图片文件,将其添加到你的文档中。 + +本指南的目标受众是所有希望了解 Mermaid 的用户,以及那些想了解如何创建图表并将其添加到 +Kubernetes 文档中的用户。 + +图 1 概要介绍的是本节所涉及的话题。 + +{{< mermaid >}} +flowchart LR +subgraph m[Mermaid.js] +direction TB +S[ ]-.- +C[使用 markdown 来
构造图表] --> +D[在线
编辑器] +end +A[为什么图表
很有用] --> m +m --> N[3 种创建
图表的方法] +N --> T[示例] +T --> X[样式
与标题] +X --> V[提示] + + + + classDef box fill:#fff,stroke:#000,stroke-width:1px,color:#000; + classDef spacewhite fill:#ffffff,stroke:#fff,stroke-width:0px,color:#000 + class A,C,D,N,X,m,T,V box + class S spacewhite + +%% you can hyperlink Mermaid diagram nodes to a URL using click statements + +click A "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZmxvd2NoYXJ0IExSXG4gICAgc3ViZ3JhcGggbVtNZXJtYWlkLmpzXVxuICAgIGRpcmVjdGlvbiBUQlxuICAgICAgICBTWyBdLS4tXG4gICAgICAgIENbYnVpbGQ8YnI-ZGlhZ3JhbXM8YnI-d2l0aCBtYXJrZG93bl0gLS0-XG4gICAgICAgIERbb24tbGluZTxicj5saXZlIGVkaXRvcl1cbiAgICBlbmRcbiAgICBBW1doeSBhcmUgZGlhZ3JhbXM8YnI-dXNlZnVsP10gLS0-IG1cbiAgICBtIC0tPiBOWzMgeCBtZXRob2RzPGJyPmZvciBjcmVhdGluZzxicj5kaWFncmFtc11cbiAgICBOIC0tPiBUW0V4YW1wbGVzXVxuICAgIFQgLS0-IFhbU3R5bGluZzxicj5hbmQ8YnI-Y2FwdGlvbnNdXG4gICAgWCAtLT4gVltUaXBzXVxuICAgIFxuIFxuICAgIGNsYXNzRGVmIGJveCBmaWxsOiNmZmYsc3Ryb2tlOiMwMDAsc3Ryb2tlLXdpZHRoOjFweCxjb2xvcjojMDAwO1xuICAgIGNsYXNzRGVmIHNwYWNld2hpdGUgZmlsbDojZmZmZmZmLHN0cm9rZTojZmZmLHN0cm9rZS13aWR0aDowcHgsY29sb3I6IzAwMFxuICAgIGNsYXNzIEEsQyxELE4sWCxtLFQsViBib3hcbiAgICBjbGFzcyBTIHNwYWNld2hpdGUiLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOnRydWV9" _blank +click C "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZmxvd2NoYXJ0IExSXG4gICAgc3ViZ3JhcGggbVtNZXJtYWlkLmpzXVxuICAgIGRpcmVjdGlvbiBUQlxuICAgICAgICBTWyBdLS4tXG4gICAgICAgIENbYnVpbGQ8YnI-ZGlhZ3JhbXM8YnI-d2l0aCBtYXJrZG93bl0gLS0-XG4gICAgICAgIERbb24tbGluZTxicj5saXZlIGVkaXRvcl1cbiAgICBlbmRcbiAgICBBW1doeSBhcmUgZGlhZ3JhbXM8YnI-dXNlZnVsP10gLS0-IG1cbiAgICBtIC0tPiBOWzMgeCBtZXRob2RzPGJyPmZvciBjcmVhdGluZzxicj5kaWFncmFtc11cbiAgICBOIC0tPiBUW0V4YW1wbGVzXVxuICAgIFQgLS0-IFhbU3R5bGluZzxicj5hbmQ8YnI-Y2FwdGlvbnNdXG4gICAgWCAtLT4gVltUaXBzXVxuICAgIFxuIFxuICAgIGNsYXNzRGVmIGJveCBmaWxsOiNmZmYsc3Ryb2tlOiMwMDAsc3Ryb2tlLXdpZHRoOjFweCxjb2xvcjojMDAwO1xuICAgIGNsYXNzRGVmIHNwYWNld2hpdGUgZmlsbDojZmZmZmZmLHN0cm9rZTojZmZmLHN0cm9rZS13aWR0aDowcHgsY29sb3I6IzAwMFxuICAgIGNsYXNzIEEsQyxELE4sWCxtLFQsViBib3hcbiAgICBjbGFzcyBTIHNwYWNld2hpdGUiLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOnRydWV9" _blank +click D "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZmxvd2NoYXJ0IExSXG4gICAgc3ViZ3JhcGggbVtNZXJtYWlkLmpzXVxuICAgIGRpcmVjdGlvbiBUQlxuICAgICAgICBTWyBdLS4tXG4gICAgICAgIENbYnVpbGQ8YnI-ZGlhZ3JhbXM8YnI-d2l0aCBtYXJrZG93bl0gLS0-XG4gICAgICAgIERbb24tbGluZTxicj5saXZlIGVkaXRvcl1cbiAgICBlbmRcbiAgICBBW1doeSBhcmUgZGlhZ3JhbXM8YnI-dXNlZnVsP10gLS0-IG1cbiAgICBtIC0tPiBOWzMgeCBtZXRob2RzPGJyPmZvciBjcmVhdGluZzxicj5kaWFncmFtc11cbiAgICBOIC0tPiBUW0V4YW1wbGVzXVxuICAgIFQgLS0-IFhbU3R5bGluZzxicj5hbmQ8YnI-Y2FwdGlvbnNdXG4gICAgWCAtLT4gVltUaXBzXVxuICAgIFxuIFxuICAgIGNsYXNzRGVmIGJveCBmaWxsOiNmZmYsc3Ryb2tlOiMwMDAsc3Ryb2tlLXdpZHRoOjFweCxjb2xvcjojMDAwO1xuICAgIGNsYXNzRGVmIHNwYWNld2hpdGUgZmlsbDojZmZmZmZmLHN0cm9rZTojZmZmLHN0cm9rZS13aWR0aDowcHgsY29sb3I6IzAwMFxuICAgIGNsYXNzIEEsQyxELE4sWCxtLFQsViBib3hcbiAgICBjbGFzcyBTIHNwYWNld2hpdGUiLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOnRydWV9" _blank +click N "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZmxvd2NoYXJ0IExSXG4gICAgc3ViZ3JhcGggbVtNZXJtYWlkLmpzXVxuICAgIGRpcmVjdGlvbiBUQlxuICAgICAgICBTWyBdLS4tXG4gICAgICAgIENbYnVpbGQ8YnI-ZGlhZ3JhbXM8YnI-d2l0aCBtYXJrZG93bl0gLS0-XG4gICAgICAgIERbb24tbGluZTxicj5saXZlIGVkaXRvcl1cbiAgICBlbmRcbiAgICBBW1doeSBhcmUgZGlhZ3JhbXM8YnI-dXNlZnVsP10gLS0-IG1cbiAgICBtIC0tPiBOWzMgeCBtZXRob2RzPGJyPmZvciBjcmVhdGluZzxicj5kaWFncmFtc11cbiAgICBOIC0tPiBUW0V4YW1wbGVzXVxuICAgIFQgLS0-IFhbU3R5bGluZzxicj5hbmQ8YnI-Y2FwdGlvbnNdXG4gICAgWCAtLT4gVltUaXBzXVxuICAgIFxuIFxuICAgIGNsYXNzRGVmIGJveCBmaWxsOiNmZmYsc3Ryb2tlOiMwMDAsc3Ryb2tlLXdpZHRoOjFweCxjb2xvcjojMDAwO1xuICAgIGNsYXNzRGVmIHNwYWNld2hpdGUgZmlsbDojZmZmZmZmLHN0cm9rZTojZmZmLHN0cm9rZS13aWR0aDowcHgsY29sb3I6IzAwMFxuICAgIGNsYXNzIEEsQyxELE4sWCxtLFQsViBib3hcbiAgICBjbGFzcyBTIHNwYWNld2hpdGUiLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOnRydWV9" _blank +click T "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZmxvd2NoYXJ0IExSXG4gICAgc3ViZ3JhcGggbVtNZXJtYWlkLmpzXVxuICAgIGRpcmVjdGlvbiBUQlxuICAgICAgICBTWyBdLS4tXG4gICAgICAgIENbYnVpbGQ8YnI-ZGlhZ3JhbXM8YnI-d2l0aCBtYXJrZG93bl0gLS0-XG4gICAgICAgIERbb24tbGluZTxicj5saXZlIGVkaXRvcl1cbiAgICBlbmRcbiAgICBBW1doeSBhcmUgZGlhZ3JhbXM8YnI-dXNlZnVsP10gLS0-IG1cbiAgICBtIC0tPiBOWzMgeCBtZXRob2RzPGJyPmZvciBjcmVhdGluZzxicj5kaWFncmFtc11cbiAgICBOIC0tPiBUW0V4YW1wbGVzXVxuICAgIFQgLS0-IFhbU3R5bGluZzxicj5hbmQ8YnI-Y2FwdGlvbnNdXG4gICAgWCAtLT4gVltUaXBzXVxuICAgIFxuIFxuICAgIGNsYXNzRGVmIGJveCBmaWxsOiNmZmYsc3Ryb2tlOiMwMDAsc3Ryb2tlLXdpZHRoOjFweCxjb2xvcjojMDAwO1xuICAgIGNsYXNzRGVmIHNwYWNld2hpdGUgZmlsbDojZmZmZmZmLHN0cm9rZTojZmZmLHN0cm9rZS13aWR0aDowcHgsY29sb3I6IzAwMFxuICAgIGNsYXNzIEEsQyxELE4sWCxtLFQsViBib3hcbiAgICBjbGFzcyBTIHNwYWNld2hpdGUiLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOnRydWV9" _blank +click X "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZmxvd2NoYXJ0IExSXG4gICAgc3ViZ3JhcGggbVtNZXJtYWlkLmpzXVxuICAgIGRpcmVjdGlvbiBUQlxuICAgICAgICBTWyBdLS4tXG4gICAgICAgIENbYnVpbGQ8YnI-ZGlhZ3JhbXM8YnI-d2l0aCBtYXJrZG93bl0gLS0-XG4gICAgICAgIERbb24tbGluZTxicj5saXZlIGVkaXRvcl1cbiAgICBlbmRcbiAgICBBW1doeSBhcmUgZGlhZ3JhbXM8YnI-dXNlZnVsP10gLS0-IG1cbiAgICBtIC0tPiBOWzMgeCBtZXRob2RzPGJyPmZvciBjcmVhdGluZzxicj5kaWFncmFtc11cbiAgICBOIC0tPiBUW0V4YW1wbGVzXVxuICAgIFQgLS0-IFhbU3R5bGluZzxicj5hbmQ8YnI-Y2FwdGlvbnNdXG4gICAgWCAtLT4gVltUaXBzXVxuICAgIFxuIFxuICAgIGNsYXNzRGVmIGJveCBmaWxsOiNmZmYsc3Ryb2tlOiMwMDAsc3Ryb2tlLXdpZHRoOjFweCxjb2xvcjojMDAwO1xuICAgIGNsYXNzRGVmIHNwYWNld2hpdGUgZmlsbDojZmZmZmZmLHN0cm9rZTojZmZmLHN0cm9rZS13aWR0aDowcHgsY29sb3I6IzAwMFxuICAgIGNsYXNzIEEsQyxELE4sWCxtLFQsViBib3hcbiAgICBjbGFzcyBTIHNwYWNld2hpdGUiLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOnRydWV9" _blank +click V "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZmxvd2NoYXJ0IExSXG4gICAgc3ViZ3JhcGggbVtNZXJtYWlkLmpzXVxuICAgIGRpcmVjdGlvbiBUQlxuICAgICAgICBTWyBdLS4tXG4gICAgICAgIENbYnVpbGQ8YnI-ZGlhZ3JhbXM8YnI-d2l0aCBtYXJrZG93bl0gLS0-XG4gICAgICAgIERbb24tbGluZTxicj5saXZlIGVkaXRvcl1cbiAgICBlbmRcbiAgICBBW1doeSBhcmUgZGlhZ3JhbXM8YnI-dXNlZnVsP10gLS0-IG1cbiAgICBtIC0tPiBOWzMgeCBtZXRob2RzPGJyPmZvciBjcmVhdGluZzxicj5kaWFncmFtc11cbiAgICBOIC0tPiBUW0V4YW1wbGVzXVxuICAgIFQgLS0-IFhbU3R5bGluZzxicj5hbmQ8YnI-Y2FwdGlvbnNdXG4gICAgWCAtLT4gVltUaXBzXVxuICAgIFxuIFxuICAgIGNsYXNzRGVmIGJveCBmaWxsOiNmZmYsc3Ryb2tlOiMwMDAsc3Ryb2tlLXdpZHRoOjFweCxjb2xvcjojMDAwO1xuICAgIGNsYXNzRGVmIHNwYWNld2hpdGUgZmlsbDojZmZmZmZmLHN0cm9rZTojZmZmLHN0cm9rZS13aWR0aDowcHgsY29sb3I6IzAwMFxuICAgIGNsYXNzIEEsQyxELE4sWCxtLFQsViBib3hcbiAgICBjbGFzcyBTIHNwYWNld2hpdGUiLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOnRydWV9" _blank + +{{< /mermaid >}} + + +图 1. 本节中涉及的话题. + + +开始使用 Mermaid 之前,你需要以下准备: + +* 对 Markdown 有一个基本的了解 +* 使用 Mermaid 在线编辑器 +* 使用 [Hugo 短代码(shortcode)](/zh/docs/contribute/style/hugo-shortcodes/) +* 使用 [Hugo {{}} 短代码](https://gohugo.io/content-management/shortcodes/#figure) +* 执行 [Hugo 本地预览](/zh/docs/contribute/new-content/open-a-pr/#preview-locally) +* 熟悉[贡献新内容](/zh/docs/contribute/new-content/)的流程 + +{{< note >}} + +你可以点击本节中的每个图表来查看其源代码,以及在 Mermaid 在线编辑器中渲染的图表结果。 +{{< /note >}} + + + + +## 你为什么应该在代码中使用图表 + +图表可以增进文档的清晰度,便于理解。对于用户和贡献者而言都有好处。 + + +用户获得的好处有: +* __较为友好的初次体验__:非常详尽的、只包含文本的欢迎页面对用户而言是蛮恐怖的, + 尤其是初次接触 Kubernetes 的用户。 +* __快速理解概念__:图表可以帮助用户理解复杂主题下的要点。 + 你的图表可以作为一种可视化的学习指南,将用户带入主题的细节。 +* __便于记忆__:对某些人而言,图形(图像)要比文字更容易记忆。 + + +对贡献者而言的好处有: + +* __帮助确立所贡献文档的结构和内容__。例如, + 你可以先提供一个覆盖所有顶层要点的图表,然后再逐步展开细节。 +* __培养用户社区并提升其能力__ 容易理解的文档,附以图表,能够吸引新的用户, + 尤其是那些因为预见到复杂性而不愿参与的用户。 + + +你需要考虑你的目标受众。除了一些有经验的 K8s 用户外,你还会遇到很多刚接触 +Kubernetes 的用户。即使一张简单的图表也可以帮助新用户吸收 Kubernetes 概念。 +他们会变得更为大胆和自信,进一步地了解 Kubernetes 及其文档。 + +## Mermaid + + +[Mermaid](https://mermaid-js.github.io/mermaid/#/) 是一个开源的 JavaScript 库, +可以帮助你创建、编辑并很容易地分享图表。这些图表使用简单的、类似 Markdown +的语法开发,并可内嵌到 Markdown 文件中。 + + +下面是 Mermaid 的一些特性: + +* 简单的编码语法 +* 包含基于 Web 的工具,便于你编制和预览你的图表 +* 支持包括流程图、状态图、时序图在内的多种格式 +* 可以通过共享图表的 URL 来与同事方便地合作 +* 有丰富的形状、线条、主题和样式可供选择 + + +使用 Mermaid 的一些好处如下: + +* 不需要使用另外的、非 Mermaid 的图表工具 +* 与现有的 PR 工作流结合的很好。你可以将 Mermaid 代码视为你的 PR 中所包含的 + Markdown 文本 +* 简单的工具生成简单的图表。你不需要精心制作或雕琢过于复杂或详尽的图片。 + 保持简单就好。 + + +Mermaid 提供一种简单的、开放且透明的方法,便于 SIG 社区为新的或现有的文档添加、 +编辑图表并展开协作。 + +{{< note >}} + +即使你的工作环境中不支持,你仍然可以使用 Mermaid 来创建、编辑图表。 +这种方法称作 __Mermaid+SVG__,在后文详细解释。 +{{< /note >}} + + +### 在线编辑器 + +[Mermaid 在线编辑器](https://mermaid-js.github.io/mermaid-live-editor)是一个基于 +Web 的工具,允许你创建、编辑和审阅图表。 + + +在线编辑器的功能主要有: + +* 显示 Mermaid 代码和渲染的图表。 +* 为所保存的每个图表生成一个 URL。该 URL 显示在你的浏览器的 URL 字段中。 + 你可以将 URL 分享给同事,便于他人访问和更改图表。 +* 提供将图表下载为 `.svg` 或 `.png` 文件的选项。 + + +{{< note >}} + +在线编辑器是创建和编辑 Mermaid 图表的最简单的,也是最快的方式。 +{{< /note >}} + + +## 创建图表的方法 {#methods-for-creating-diagrams} + +图 2 给出三种生成和添加图表的方法。 + +{{< mermaid >}} +graph TB +A[贡献者] +B[向 .md 文件

中内嵌
Mermaid 代码] +C[Mermaid+SVG

将 Mermaid 所生成的
SVG 文件添加到 .md 文件] +D[外部工具

添加外部工具
所生成的 SVG
文件到 .md 文件] + + A --> B + A --> C + A --> D + + classDef box fill:#fff,stroke:#000,stroke-width:1px,color:#000; + class A,B,C,D box + +%% 你可以使用 click 语句为 Mermaid 节点设置指向某 URL 的超链接 + +click A "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZ3JhcGggVEJcbiAgICBBW0NvbnRyaWJ1dG9yXVxuICAgIEJbSW5saW5lPGJyPjxicj5NZXJtYWlkIGNvZGU8YnI-YWRkZWQgdG8gLm1kIGZpbGVdXG4gICAgQ1tNZXJtYWlkK1NWRzxicj48YnI-QWRkIG1lcm1haWQtZ2VuZXJhdGVkPGJyPnN2ZyBmaWxlIHRvIC5tZCBmaWxlXVxuICAgIERbRXh0ZXJuYWwgdG9vbDxicj48YnI-QWRkIGV4dGVybmFsLXRvb2wtPGJyPmdlbmVyYXRlZCBzdmcgZmlsZTxicj50byAubWQgZmlsZV1cblxuICAgIEEgLS0-IEJcbiAgICBBIC0tPiBDXG4gICAgQSAtLT4gRFxuXG4gICAgY2xhc3NEZWYgYm94IGZpbGw6I2ZmZixzdHJva2U6IzAwMCxzdHJva2Utd2lkdGg6MXB4LGNvbG9yOiMwMDA7XG4gICAgY2xhc3MgQSxCLEMsRCBib3giLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOmZhbHNlfQ" _blank + +click B "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZ3JhcGggVEJcbiAgICBBW0NvbnRyaWJ1dG9yXVxuICAgIEJbSW5saW5lPGJyPjxicj5NZXJtYWlkIGNvZGU8YnI-YWRkZWQgdG8gLm1kIGZpbGVdXG4gICAgQ1tNZXJtYWlkK1NWRzxicj48YnI-QWRkIG1lcm1haWQtZ2VuZXJhdGVkPGJyPnN2ZyBmaWxlIHRvIC5tZCBmaWxlXVxuICAgIERbRXh0ZXJuYWwgdG9vbDxicj48YnI-QWRkIGV4dGVybmFsLXRvb2wtPGJyPmdlbmVyYXRlZCBzdmcgZmlsZTxicj50byAubWQgZmlsZV1cblxuICAgIEEgLS0-IEJcbiAgICBBIC0tPiBDXG4gICAgQSAtLT4gRFxuXG4gICAgY2xhc3NEZWYgYm94IGZpbGw6I2ZmZixzdHJva2U6IzAwMCxzdHJva2Utd2lkdGg6MXB4LGNvbG9yOiMwMDA7XG4gICAgY2xhc3MgQSxCLEMsRCBib3giLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOmZhbHNlfQ" _blank + +click C "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZ3JhcGggVEJcbiAgICBBW0NvbnRyaWJ1dG9yXVxuICAgIEJbSW5saW5lPGJyPjxicj5NZXJtYWlkIGNvZGU8YnI-YWRkZWQgdG8gLm1kIGZpbGVdXG4gICAgQ1tNZXJtYWlkK1NWRzxicj48YnI-QWRkIG1lcm1haWQtZ2VuZXJhdGVkPGJyPnN2ZyBmaWxlIHRvIC5tZCBmaWxlXVxuICAgIERbRXh0ZXJuYWwgdG9vbDxicj48YnI-QWRkIGV4dGVybmFsLXRvb2wtPGJyPmdlbmVyYXRlZCBzdmcgZmlsZTxicj50byAubWQgZmlsZV1cblxuICAgIEEgLS0-IEJcbiAgICBBIC0tPiBDXG4gICAgQSAtLT4gRFxuXG4gICAgY2xhc3NEZWYgYm94IGZpbGw6I2ZmZixzdHJva2U6IzAwMCxzdHJva2Utd2lkdGg6MXB4LGNvbG9yOiMwMDA7XG4gICAgY2xhc3MgQSxCLEMsRCBib3giLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOmZhbHNlfQ" _blank + +click D "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZ3JhcGggVEJcbiAgICBBW0NvbnRyaWJ1dG9yXVxuICAgIEJbSW5saW5lPGJyPjxicj5NZXJtYWlkIGNvZGU8YnI-YWRkZWQgdG8gLm1kIGZpbGVdXG4gICAgQ1tNZXJtYWlkK1NWRzxicj48YnI-QWRkIG1lcm1haWQtZ2VuZXJhdGVkPGJyPnN2ZyBmaWxlIHRvIC5tZCBmaWxlXVxuICAgIERbRXh0ZXJuYWwgdG9vbDxicj48YnI-QWRkIGV4dGVybmFsLXRvb2wtPGJyPmdlbmVyYXRlZCBzdmcgZmlsZTxicj50byAubWQgZmlsZV1cblxuICAgIEEgLS0-IEJcbiAgICBBIC0tPiBDXG4gICAgQSAtLT4gRFxuXG4gICAgY2xhc3NEZWYgYm94IGZpbGw6I2ZmZixzdHJva2U6IzAwMCxzdHJva2Utd2lkdGg6MXB4LGNvbG9yOiMwMDA7XG4gICAgY2xhc3MgQSxCLEMsRCBib3giLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOmZhbHNlfQ" _blank + +{{< /mermaid >}} + + +图 2. 创建图表的方法 + + + +### 内嵌(Inline) + +图 3 给出的是使用内嵌方法来添加图表所遵循的步骤。 + +{{< mermaid >}} +graph LR +A[1. 使用在线编辑器
来创建或编辑
图表] --> +B[2. 将图表的 URL
保存到某处] --> +C[3. 将 Mermaid 代码
复制到 markdown 文件中] --> +D[4. 添加图表标题] + + + classDef box fill:#fff,stroke:#000,stroke-width:1px,color:#000; + class A,B,C,D box + +%% 你可以使用 click 语句为 Mermaid 节点设置指向某 URL 的超链接 + +click A "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZ3JhcGggTFJcbiAgICBBWzEuIFVzZSBsaXZlIGVkaXRvcjxicj4gdG8gY3JlYXRlL2VkaXQ8YnI-ZGlhZ3JhbV0gLS0-XG4gICAgQlsyLiBTdG9yZSBkaWFncmFtPGJyPlVSTCBzb21ld2hlcmVdIC0tPlxuICAgIENbMy4gQ29weSBNZXJtYWlkIGNvZGU8YnI-dG8gcGFnZSBtYXJrZG93biBmaWxlXSAtLT5cbiAgICBEWzQuIEFkZCBjYXB0aW9uXVxuIFxuXG4gICAgY2xhc3NEZWYgYm94IGZpbGw6I2ZmZixzdHJva2U6IzAwMCxzdHJva2Utd2lkdGg6MXB4LGNvbG9yOiMwMDA7XG4gICAgY2xhc3MgQSxCLEMsRCBib3hcbiAgICAiLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOmZhbHNlfQ" _blank + +click B "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZ3JhcGggTFJcbiAgICBBWzEuIFVzZSBsaXZlIGVkaXRvcjxicj4gdG8gY3JlYXRlL2VkaXQ8YnI-ZGlhZ3JhbV0gLS0-XG4gICAgQlsyLiBTdG9yZSBkaWFncmFtPGJyPlVSTCBzb21ld2hlcmVdIC0tPlxuICAgIENbMy4gQ29weSBNZXJtYWlkIGNvZGU8YnI-dG8gcGFnZSBtYXJrZG93biBmaWxlXSAtLT5cbiAgICBEWzQuIEFkZCBjYXB0aW9uXVxuIFxuXG4gICAgY2xhc3NEZWYgYm94IGZpbGw6I2ZmZixzdHJva2U6IzAwMCxzdHJva2Utd2lkdGg6MXB4LGNvbG9yOiMwMDA7XG4gICAgY2xhc3MgQSxCLEMsRCBib3hcbiAgICAiLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOmZhbHNlfQ" _blank + +click C "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZ3JhcGggTFJcbiAgICBBWzEuIFVzZSBsaXZlIGVkaXRvcjxicj4gdG8gY3JlYXRlL2VkaXQ8YnI-ZGlhZ3JhbV0gLS0-XG4gICAgQlsyLiBTdG9yZSBkaWFncmFtPGJyPlVSTCBzb21ld2hlcmVdIC0tPlxuICAgIENbMy4gQ29weSBNZXJtYWlkIGNvZGU8YnI-dG8gcGFnZSBtYXJrZG93biBmaWxlXSAtLT5cbiAgICBEWzQuIEFkZCBjYXB0aW9uXVxuIFxuXG4gICAgY2xhc3NEZWYgYm94IGZpbGw6I2ZmZixzdHJva2U6IzAwMCxzdHJva2Utd2lkdGg6MXB4LGNvbG9yOiMwMDA7XG4gICAgY2xhc3MgQSxCLEMsRCBib3hcbiAgICAiLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOmZhbHNlfQ" _blank + +click D "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZ3JhcGggTFJcbiAgICBBWzEuIFVzZSBsaXZlIGVkaXRvcjxicj4gdG8gY3JlYXRlL2VkaXQ8YnI-ZGlhZ3JhbV0gLS0-XG4gICAgQlsyLiBTdG9yZSBkaWFncmFtPGJyPlVSTCBzb21ld2hlcmVdIC0tPlxuICAgIENbMy4gQ29weSBNZXJtYWlkIGNvZGU8YnI-dG8gcGFnZSBtYXJrZG93biBmaWxlXSAtLT5cbiAgICBEWzQuIEFkZCBjYXB0aW9uXVxuIFxuXG4gICAgY2xhc3NEZWYgYm94IGZpbGw6I2ZmZixzdHJva2U6IzAwMCxzdHJva2Utd2lkdGg6MXB4LGNvbG9yOiMwMDA7XG4gICAgY2xhc3MgQSxCLEMsRCBib3hcbiAgICAiLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOmZhbHNlfQ" _blank + +{{< /mermaid >}} + + +图 3. 内嵌方法的步骤 + + +下面是使用内嵌方法来添加图表时你要执行的步骤: + +1. 使用在线编辑器创建你的图表 +1. 将图表的 URL 保存在某处以便以后访问 +1. 将 Mermaid 代码复制到你的 `.md` 文件中你希望它出现的位置 +1. 使用 Markdown 文本在图表下方为其添加标题 + + +Hugo 在构造(网站)过程中会运行 Mermaid 代码,将其转换为图表。 + +{{< note >}} + +你可能认为记录图表 URL 是一个麻烦的过程。如果确实如此,你可以在 `.md` 文件中作一个记录, +标明该 Mermaid 代码是自说明的。贡献者可以将 Mermaid 代码复制到在线编辑器中编辑, +或者将其从在线编辑器中复制出来。 +{{< /note >}} + + +下面是一段包含在某 `.md` 文件中的示例代码片段: + +``` +--- +title: 我的文档 +--- +Figure 17 给出从 A 到 B 的一个简单流程。 +这里是其他 markdown 文本 +... +{{}} + graph TB + A --> B +{{}} + +图 17. 从 A 到 B + +其他文本 +``` + +{{< note >}} + +你必须在 Mermaid 代码块之前和之后分别添加 `{{}}`、`{{}}` +短代码标记,而且你应该在图表之后为其添加图表标题。 +{{< /note >}} + + +有关添加图表标题的细节,参阅[如何使用标题](#how-to-use-captions)。 + + +使用内嵌方法的好处有: + +* 可以直接使用在线编辑器工具 +* 很容易在在线编辑器与你的 `.md` 文件之间来回复制 Mermaid 代码 +* 不需要额外处理 `.svg` 图片文件 +* 内容文字、图表代码和图表标题都位于同一个 `.md` 文件中。 + + +你应该使用[本地](/zh/docs/contribute/new-content/open-a-pr/#preview-locally)和 Netlify +预览来验证图表是可以正常渲染的。 + +{{< caution >}} + +Mermaid 在线编辑器的功能特性可能不支持 K8s 网站的 Mermaid 特性。 +你可能在 Hugo 构建过程中看到语法错误提示或者空白屏幕。 +如果发生这类情况,可以考虑使用 Mermaid+SVG 方法。 +{{< /caution >}} + +### Mermaid+SVG + + +图 4 给出的是使用 Mermaid+SVG 方法添加图表所要遵循的步骤: + +{{< mermaid >}} +flowchart LR +A[1. 使用在线编辑器
创建或编辑
图表] +B[2. 将图表的 URL
保存到别处] +C[3. 生成 .svg 文件
并将其下载到
images/ 目录] +subgraph w[ ] +direction TB +D[4. 使用 figure 短代码
来在 .md 文件中
引用 .svg 文件] --> +E[5. 添加图表标题] +end +A --> B +B --> C +C --> w + + classDef box fill:#fff,stroke:#000,stroke-width:1px,color:#000; + class A,B,C,D,E,w box + +click A "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZmxvd2NoYXJ0IExSXG4gICAgQVsxLiBVc2UgbGl2ZSBlZGl0b3I8YnI-IHRvIGNyZWF0ZS9lZGl0PGJyPmRpYWdyYW1dXG4gICAgQlsyLiBTdG9yZSBkaWFncmFtPGJyPlVSTCBzb21ld2hlcmVdXG4gICAgQ1szLiBHZW5lcmF0ZSAuc3ZnIGZpbGU8YnI-YW5kIGRvd25sb2FkIHRvPGJyPmltYWdlcy8gZm9sZGVyXVxuICAgIHN1YmdyYXBoIHdbIF1cbiAgICBkaXJlY3Rpb24gVEJcbiAgICBEWzQuIFVzZSBmaWd1cmUgc2hvcnRjb2RlPGJyPnRvIHJlZmVyZW5jZSAuc3ZnPGJyPmZpbGUgaW4gcGFnZTxicj4ubWQgZmlsZV0gLS0-XG4gICAgRVs1LiBBZGQgY2FwdGlvbl1cbiAgICBlbmRcbkEgLS0-IEJcbkIgLS0-IENcbkMgLS0-IHdcblxuICAgIGNsYXNzRGVmIGJveCBmaWxsOiNmZmYsc3Ryb2tlOiMwMDAsc3Ryb2tlLXdpZHRoOjFweCxjb2xvcjojMDAwO1xuICAgIGNsYXNzIEEsQixDLEQsRSx3IGJveFxuICAgICIsIm1lcm1haWQiOiJ7XG4gIFwidGhlbWVcIjogXCJkZWZhdWx0XCJcbn0iLCJ1cGRhdGVFZGl0b3IiOmZhbHNlLCJhdXRvU3luYyI6dHJ1ZSwidXBkYXRlRGlhZ3JhbSI6dHJ1ZX0" _blank + +click B "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZmxvd2NoYXJ0IExSXG4gICAgQVsxLiBVc2UgbGl2ZSBlZGl0b3I8YnI-IHRvIGNyZWF0ZS9lZGl0PGJyPmRpYWdyYW1dXG4gICAgQlsyLiBTdG9yZSBkaWFncmFtPGJyPlVSTCBzb21ld2hlcmVdXG4gICAgQ1szLiBHZW5lcmF0ZSAuc3ZnIGZpbGU8YnI-YW5kIGRvd25sb2FkIHRvPGJyPmltYWdlcy8gZm9sZGVyXVxuICAgIHN1YmdyYXBoIHdbIF1cbiAgICBkaXJlY3Rpb24gVEJcbiAgICBEWzQuIFVzZSBmaWd1cmUgc2hvcnRjb2RlPGJyPnRvIHJlZmVyZW5jZSAuc3ZnPGJyPmZpbGUgaW4gcGFnZTxicj4ubWQgZmlsZV0gLS0-XG4gICAgRVs1LiBBZGQgY2FwdGlvbl1cbiAgICBlbmRcbkEgLS0-IEJcbkIgLS0-IENcbkMgLS0-IHdcblxuICAgIGNsYXNzRGVmIGJveCBmaWxsOiNmZmYsc3Ryb2tlOiMwMDAsc3Ryb2tlLXdpZHRoOjFweCxjb2xvcjojMDAwO1xuICAgIGNsYXNzIEEsQixDLEQsRSx3IGJveFxuICAgICIsIm1lcm1haWQiOiJ7XG4gIFwidGhlbWVcIjogXCJkZWZhdWx0XCJcbn0iLCJ1cGRhdGVFZGl0b3IiOmZhbHNlLCJhdXRvU3luYyI6dHJ1ZSwidXBkYXRlRGlhZ3JhbSI6dHJ1ZX0" _blank + +click C "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZmxvd2NoYXJ0IExSXG4gICAgQVsxLiBVc2UgbGl2ZSBlZGl0b3I8YnI-IHRvIGNyZWF0ZS9lZGl0PGJyPmRpYWdyYW1dXG4gICAgQlsyLiBTdG9yZSBkaWFncmFtPGJyPlVSTCBzb21ld2hlcmVdXG4gICAgQ1szLiBHZW5lcmF0ZSAuc3ZnIGZpbGU8YnI-YW5kIGRvd25sb2FkIHRvPGJyPmltYWdlcy8gZm9sZGVyXVxuICAgIHN1YmdyYXBoIHdbIF1cbiAgICBkaXJlY3Rpb24gVEJcbiAgICBEWzQuIFVzZSBmaWd1cmUgc2hvcnRjb2RlPGJyPnRvIHJlZmVyZW5jZSAuc3ZnPGJyPmZpbGUgaW4gcGFnZTxicj4ubWQgZmlsZV0gLS0-XG4gICAgRVs1LiBBZGQgY2FwdGlvbl1cbiAgICBlbmRcbkEgLS0-IEJcbkIgLS0-IENcbkMgLS0-IHdcblxuICAgIGNsYXNzRGVmIGJveCBmaWxsOiNmZmYsc3Ryb2tlOiMwMDAsc3Ryb2tlLXdpZHRoOjFweCxjb2xvcjojMDAwO1xuICAgIGNsYXNzIEEsQixDLEQsRSx3IGJveFxuICAgICIsIm1lcm1haWQiOiJ7XG4gIFwidGhlbWVcIjogXCJkZWZhdWx0XCJcbn0iLCJ1cGRhdGVFZGl0b3IiOmZhbHNlLCJhdXRvU3luYyI6dHJ1ZSwidXBkYXRlRGlhZ3JhbSI6dHJ1ZX0" _blank + +click D "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZmxvd2NoYXJ0IExSXG4gICAgQVsxLiBVc2UgbGl2ZSBlZGl0b3I8YnI-IHRvIGNyZWF0ZS9lZGl0PGJyPmRpYWdyYW1dXG4gICAgQlsyLiBTdG9yZSBkaWFncmFtPGJyPlVSTCBzb21ld2hlcmVdXG4gICAgQ1szLiBHZW5lcmF0ZSAuc3ZnIGZpbGU8YnI-YW5kIGRvd25sb2FkIHRvPGJyPmltYWdlcy8gZm9sZGVyXVxuICAgIHN1YmdyYXBoIHdbIF1cbiAgICBkaXJlY3Rpb24gVEJcbiAgICBEWzQuIFVzZSBmaWd1cmUgc2hvcnRjb2RlPGJyPnRvIHJlZmVyZW5jZSAuc3ZnPGJyPmZpbGUgaW4gcGFnZTxicj4ubWQgZmlsZV0gLS0-XG4gICAgRVs1LiBBZGQgY2FwdGlvbl1cbiAgICBlbmRcbkEgLS0-IEJcbkIgLS0-IENcbkMgLS0-IHdcblxuICAgIGNsYXNzRGVmIGJveCBmaWxsOiNmZmYsc3Ryb2tlOiMwMDAsc3Ryb2tlLXdpZHRoOjFweCxjb2xvcjojMDAwO1xuICAgIGNsYXNzIEEsQixDLEQsRSx3IGJveFxuICAgICIsIm1lcm1haWQiOiJ7XG4gIFwidGhlbWVcIjogXCJkZWZhdWx0XCJcbn0iLCJ1cGRhdGVFZGl0b3IiOmZhbHNlLCJhdXRvU3luYyI6dHJ1ZSwidXBkYXRlRGlhZ3JhbSI6dHJ1ZX0" _blank + +click E "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZmxvd2NoYXJ0IExSXG4gICAgQVsxLiBVc2UgbGl2ZSBlZGl0b3I8YnI-IHRvIGNyZWF0ZS9lZGl0PGJyPmRpYWdyYW1dXG4gICAgQlsyLiBTdG9yZSBkaWFncmFtPGJyPlVSTCBzb21ld2hlcmVdXG4gICAgQ1szLiBHZW5lcmF0ZSAuc3ZnIGZpbGU8YnI-YW5kIGRvd25sb2FkIHRvPGJyPmltYWdlcy8gZm9sZGVyXVxuICAgIHN1YmdyYXBoIHdbIF1cbiAgICBkaXJlY3Rpb24gVEJcbiAgICBEWzQuIFVzZSBmaWd1cmUgc2hvcnRjb2RlPGJyPnRvIHJlZmVyZW5jZSAuc3ZnPGJyPmZpbGUgaW4gcGFnZTxicj4ubWQgZmlsZV0gLS0-XG4gICAgRVs1LiBBZGQgY2FwdGlvbl1cbiAgICBlbmRcbkEgLS0-IEJcbkIgLS0-IENcbkMgLS0-IHdcblxuICAgIGNsYXNzRGVmIGJveCBmaWxsOiNmZmYsc3Ryb2tlOiMwMDAsc3Ryb2tlLXdpZHRoOjFweCxjb2xvcjojMDAwO1xuICAgIGNsYXNzIEEsQixDLEQsRSx3IGJveFxuICAgICIsIm1lcm1haWQiOiJ7XG4gIFwidGhlbWVcIjogXCJkZWZhdWx0XCJcbn0iLCJ1cGRhdGVFZGl0b3IiOmZhbHNlLCJhdXRvU3luYyI6dHJ1ZSwidXBkYXRlRGlhZ3JhbSI6dHJ1ZX0" _blank + + +{{< /mermaid >}} + + +图 4. Mermaid+SVG 方法的步骤。 + + +使用 Mermaid+SVG 方法来添加图表时你要遵从的步骤: + +1. 使用在线编辑器创建你的图表 +1. 将图表的 URL 保存到某处以便以后访问 +1. 为你的图表生成 `.svg` 文件,并将其下载到合适的 `images/` 目录下 +1. 使用 `{{}}` 短代码在 `.md` 文件中引用该图表 +1. 使用 `{{}}` 短代码的 `caption` 参数为图表设置标题 + + +例如,使用在线编辑器创建一个名为 `boxnet` 的图表。 +将图表的 URL 保存到别处以便以后访问。生成 `boxnet.svg` 文件并将其下载到合适的 +`../images/` 目录下。 + + +在你的 PR 中的 `.md` 文件内使用 `{{}}` 短代码来引用 +`.svg` 图片文件,并为之添加标题。 + + +```json +{{}} +``` + + +关于图表标题的细节,可参阅[如何使用标题](#how-to-use-captions)。 + +{{< note >}} + +使用 `{{}}` 短代码是向你的文档中添加 `.svg` 图片文件的优选方法。 +你也可以使用标准的 markdown 图片语法,即 +`![my boxnet diagram](static/images/boxnet.svg)`。 +如果是后面这种,则需要在图表下面为其添加标题。 +{{< /note >}} + + +你应该使用文本编辑器以注释块的形式在 `.svg` 图片文件中添加在线编辑器的 URL。 +例如,你应该在 `.svg` 图片文件的开头部分包含下面的内容: + +``` + + +``` + + +使用 Mermaid+SVG 方法的好处有: + +* 可以直接使用在线编辑器工具 +* 在线编辑器支持的 Mermaid 特性集合最新 +* 可以利用 K8s 网站用来处理 `.svg` 图片文件的现有方法 +* 工作环境不需要 Mermaid 支持 + + +要使用[本地](/zh/docs/contribute/new-content/open-a-pr/#preview-locally)和 +Netlify 预览来检查你的图表可以正常渲染。 + + +### 外部工具 + +图 5 给出使用外部工具来添加图表时所遵循的步骤。 + +首先,要使用你的外部工具来创建图表,并将其保存为一个 `.svg` 文件或 `.png` 图片文件。 +之后,使用 __Mermaid+SVG__ 方法中相同的步骤添加 `.svg`(`.png`)文件。 + +{{< mermaid >}} +flowchart LR + +A[1. 使用外部工具
来创建或编辑
图表] +B[2. 如果可能保存
图表位置供
其他贡献者访问] +C[3. 生成 .svg 文件
或 .png 文件
并将其下载到
合适的 images/ 目录] + +subgraph w[ ] +direction TB +D[4. 使用 figure 短代码
在你的 .md 文件中
引用该 SVG 或 PNG
文件] --> +E[5. 为图表添加标题] +end +A --> B +B --> C +C --> w + + classDef box fill:#fff,stroke:#000,stroke-width:1px,color:#000; + class A,B,C,D,E,w box + +click A "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZmxvd2NoYXJ0IExSXG4gICAgQVsxLiBVc2UgZXh0ZXJuYWw8YnI-dG9vbCB0byBjcmVhdGUvZWRpdDxicj5kaWFncmFtXVxuICAgIEJbMi4gSWYgcG9zc2libGUsIHNhdmU8YnI-ZGlhZ3JhbSBjb29yZGluYXRlczxicj5mb3IgY29udHJpYnV0b3I8YnI-YWNjZXNzXVxuICAgIENbMy4gR2VuZXJhdGUgLnN2ZyA8YnI-b3IucG5nIGZpbGU8YnI-YW5kIGRvd25sb2FkIHRvPGJyPmFwcHJvcHJpYXRlPGJyPmltYWdlcy8gZm9sZGVyXVxuICAgIHN1YmdyYXBoIHdbIF1cbiAgICBkaXJlY3Rpb24gVEJcbiAgICBEWzQuIFVzZSBmaWd1cmUgc2hvcnRjb2RlPGJyPnRvIHJlZmVyZW5jZSBzdmcgb3I8YnI-cG5nIGZpbGUgaW48YnI-cGFnZSAubWQgZmlsZV0gLS0-XG4gICAgRVs1LiBBZGQgY2FwdGlvbl1cbiAgICBlbmRcbiAgICBBIC0tPiBCXG4gICAgQiAtLT4gQ1xuICAgIEMgLS0-IHdcbiAgICBjbGFzc0RlZiBib3ggZmlsbDojZmZmLHN0cm9rZTojMDAwLHN0cm9rZS13aWR0aDoxcHgsY29sb3I6IzAwMDtcbiAgICBjbGFzcyBBLEIsQyxELEUsdyBib3hcbiAgICAiLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOmZhbHNlfQ" + +click B "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZmxvd2NoYXJ0IExSXG4gICAgQVsxLiBVc2UgZXh0ZXJuYWw8YnI-dG9vbCB0byBjcmVhdGUvZWRpdDxicj5kaWFncmFtXVxuICAgIEJbMi4gSWYgcG9zc2libGUsIHNhdmU8YnI-ZGlhZ3JhbSBjb29yZGluYXRlczxicj5mb3IgY29udHJpYnV0b3I8YnI-YWNjZXNzXVxuICAgIENbMy4gR2VuZXJhdGUgLnN2ZyA8YnI-b3IucG5nIGZpbGU8YnI-YW5kIGRvd25sb2FkIHRvPGJyPmFwcHJvcHJpYXRlPGJyPmltYWdlcy8gZm9sZGVyXVxuICAgIHN1YmdyYXBoIHdbIF1cbiAgICBkaXJlY3Rpb24gVEJcbiAgICBEWzQuIFVzZSBmaWd1cmUgc2hvcnRjb2RlPGJyPnRvIHJlZmVyZW5jZSBzdmcgb3I8YnI-cG5nIGZpbGUgaW48YnI-cGFnZSAubWQgZmlsZV0gLS0-XG4gICAgRVs1LiBBZGQgY2FwdGlvbl1cbiAgICBlbmRcbiAgICBBIC0tPiBCXG4gICAgQiAtLT4gQ1xuICAgIEMgLS0-IHdcbiAgICBjbGFzc0RlZiBib3ggZmlsbDojZmZmLHN0cm9rZTojMDAwLHN0cm9rZS13aWR0aDoxcHgsY29sb3I6IzAwMDtcbiAgICBjbGFzcyBBLEIsQyxELEUsdyBib3hcbiAgICAiLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOmZhbHNlfQ" + +click C "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZmxvd2NoYXJ0IExSXG4gICAgQVsxLiBVc2UgZXh0ZXJuYWw8YnI-dG9vbCB0byBjcmVhdGUvZWRpdDxicj5kaWFncmFtXVxuICAgIEJbMi4gSWYgcG9zc2libGUsIHNhdmU8YnI-ZGlhZ3JhbSBjb29yZGluYXRlczxicj5mb3IgY29udHJpYnV0b3I8YnI-YWNjZXNzXVxuICAgIENbMy4gR2VuZXJhdGUgLnN2ZyA8YnI-b3IucG5nIGZpbGU8YnI-YW5kIGRvd25sb2FkIHRvPGJyPmFwcHJvcHJpYXRlPGJyPmltYWdlcy8gZm9sZGVyXVxuICAgIHN1YmdyYXBoIHdbIF1cbiAgICBkaXJlY3Rpb24gVEJcbiAgICBEWzQuIFVzZSBmaWd1cmUgc2hvcnRjb2RlPGJyPnRvIHJlZmVyZW5jZSBzdmcgb3I8YnI-cG5nIGZpbGUgaW48YnI-cGFnZSAubWQgZmlsZV0gLS0-XG4gICAgRVs1LiBBZGQgY2FwdGlvbl1cbiAgICBlbmRcbiAgICBBIC0tPiBCXG4gICAgQiAtLT4gQ1xuICAgIEMgLS0-IHdcbiAgICBjbGFzc0RlZiBib3ggZmlsbDojZmZmLHN0cm9rZTojMDAwLHN0cm9rZS13aWR0aDoxcHgsY29sb3I6IzAwMDtcbiAgICBjbGFzcyBBLEIsQyxELEUsdyBib3hcbiAgICAiLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOmZhbHNlfQ" + +click D "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZmxvd2NoYXJ0IExSXG4gICAgQVsxLiBVc2UgZXh0ZXJuYWw8YnI-dG9vbCB0byBjcmVhdGUvZWRpdDxicj5kaWFncmFtXVxuICAgIEJbMi4gSWYgcG9zc2libGUsIHNhdmU8YnI-ZGlhZ3JhbSBjb29yZGluYXRlczxicj5mb3IgY29udHJpYnV0b3I8YnI-YWNjZXNzXVxuICAgIENbMy4gR2VuZXJhdGUgLnN2ZyA8YnI-b3IucG5nIGZpbGU8YnI-YW5kIGRvd25sb2FkIHRvPGJyPmFwcHJvcHJpYXRlPGJyPmltYWdlcy8gZm9sZGVyXVxuICAgIHN1YmdyYXBoIHdbIF1cbiAgICBkaXJlY3Rpb24gVEJcbiAgICBEWzQuIFVzZSBmaWd1cmUgc2hvcnRjb2RlPGJyPnRvIHJlZmVyZW5jZSBzdmcgb3I8YnI-cG5nIGZpbGUgaW48YnI-cGFnZSAubWQgZmlsZV0gLS0-XG4gICAgRVs1LiBBZGQgY2FwdGlvbl1cbiAgICBlbmRcbiAgICBBIC0tPiBCXG4gICAgQiAtLT4gQ1xuICAgIEMgLS0-IHdcbiAgICBjbGFzc0RlZiBib3ggZmlsbDojZmZmLHN0cm9rZTojMDAwLHN0cm9rZS13aWR0aDoxcHgsY29sb3I6IzAwMDtcbiAgICBjbGFzcyBBLEIsQyxELEUsdyBib3hcbiAgICAiLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOmZhbHNlfQ" + +click E "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZmxvd2NoYXJ0IExSXG4gICAgQVsxLiBVc2UgZXh0ZXJuYWw8YnI-dG9vbCB0byBjcmVhdGUvZWRpdDxicj5kaWFncmFtXVxuICAgIEJbMi4gSWYgcG9zc2libGUsIHNhdmU8YnI-ZGlhZ3JhbSBjb29yZGluYXRlczxicj5mb3IgY29udHJpYnV0b3I8YnI-YWNjZXNzXVxuICAgIENbMy4gR2VuZXJhdGUgLnN2ZyA8YnI-b3IucG5nIGZpbGU8YnI-YW5kIGRvd25sb2FkIHRvPGJyPmFwcHJvcHJpYXRlPGJyPmltYWdlcy8gZm9sZGVyXVxuICAgIHN1YmdyYXBoIHdbIF1cbiAgICBkaXJlY3Rpb24gVEJcbiAgICBEWzQuIFVzZSBmaWd1cmUgc2hvcnRjb2RlPGJyPnRvIHJlZmVyZW5jZSBzdmcgb3I8YnI-cG5nIGZpbGUgaW48YnI-cGFnZSAubWQgZmlsZV0gLS0-XG4gICAgRVs1LiBBZGQgY2FwdGlvbl1cbiAgICBlbmRcbiAgICBBIC0tPiBCXG4gICAgQiAtLT4gQ1xuICAgIEMgLS0-IHdcbiAgICBjbGFzc0RlZiBib3ggZmlsbDojZmZmLHN0cm9rZTojMDAwLHN0cm9rZS13aWR0aDoxcHgsY29sb3I6IzAwMDtcbiAgICBjbGFzcyBBLEIsQyxELEUsdyBib3hcbiAgICAiLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOmZhbHNlfQ" + + +{{< /mermaid >}} + + +图 5. 外部工具方法步骤. + + +使用外部工具方法来添加图表时,你要遵从的步骤如下: + +1. 使用你的外部工具来创建图表。 +1. 将图表的位置保存起来供其他贡献者访问。例如,你的工具可能提供一个指向图表的链接, + 或者你可以将源码文件(例如一个 `.xml` 文件)放置到一个公开的仓库, + 以便其他贡献者访问。 +1. 生成图表并将其下载为 `.svg` 或 `.png` 图片文件,保存到合适的 `../images/` 目录下。 +1. 使用 `{{}}` 短代码从 `.md` 文件中引用该图表。 +5. 使用 `{{}}` 短代码的 `caption` 参数为图表设置标题。 + + +下面是一个用于 `images/apple.svg` 图表的 `{{}}` 短代码: + + +```text +{{}} +``` + + +如果你的外部绘图工具支持: + +* 你可以将多个 `.svg` 或 `.png` 商标、图标或图片整合到你的图表中。 + 不过,你需要确保你查看了版权并遵守了 Kubernetes 文档关于使用第三方内容的 + [指南](/zh/docs/contribute/style/content-guide/)。 +* 你应该将图表的源位置保存起来,以便其他贡献者访问。 + 例如,你的工具可能提供指向图表文件的链接,或者你应该将源代码文件 + (例如一个 `.xml` 文件)放到某处以便其他贡献者访问。 + + +关于 K8s 和 CNCF 商标与图片的详细信息,可参阅 [CNCF Artwork](https://github.com/cncf/artwork)。 + + +使用外部工具的好处有: + +* 贡献者对外部工具更为熟悉 +* 图表可能需要 Mermaid 所无法提供的细节 + +不要忘记使用[本地](/zh/docs/contribute/new-content/open-a-pr/#preview-locally) +和 Netlify 预览来检查你的图表可以正常渲染。 + + +## 示例 + +本节给出 Mermaid 的若干样例。 + +{{< note >}} + +代码块示例中忽略了 Hugo `{{}}`、`{{}}` 短代码标记。 +这样,你就可以将这些代码段复制到在线编辑器中自行实验。 +注意,在线编辑器无法识别 Hugo 短代码。 +{{< /note >}} + + +### 示例 1 - Pod 拓扑分布约束 + +图 6 展示的是 [Pod 拓扑分布约束](/zh/docs/concepts/workloads/pods/pod-topology-spread-constraints/#node-labels) +页面所出现的图表。 + +{{< mermaid >}} + graph TB + subgraph "zoneB" + n3(Node3) + n4(Node4) + end + subgraph "zoneA" + n1(Node1) + n2(Node2) + end + + classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000; + classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff; + classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5; + class n1,n2,n3,n4 k8s; + class zoneA,zoneB cluster; + +click n3 "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZ3JhcGggVEJcbiAgICBzdWJncmFwaCBcInpvbmVCXCJcbiAgICAgICAgbjMoTm9kZTMpXG4gICAgICAgIG40KE5vZGU0KVxuICAgIGVuZFxuICAgIHN1YmdyYXBoIFwiem9uZUFcIlxuICAgICAgICBuMShOb2RlMSlcbiAgICAgICAgbjIoTm9kZTIpXG4gICAgZW5kXG5cbiAgICBjbGFzc0RlZiBwbGFpbiBmaWxsOiNkZGQsc3Ryb2tlOiNmZmYsc3Ryb2tlLXdpZHRoOjRweCxjb2xvcjojMDAwO1xuICAgIGNsYXNzRGVmIGs4cyBmaWxsOiMzMjZjZTUsc3Ryb2tlOiNmZmYsc3Ryb2tlLXdpZHRoOjRweCxjb2xvcjojZmZmO1xuICAgIGNsYXNzRGVmIGNsdXN0ZXIgZmlsbDojZmZmLHN0cm9rZTojYmJiLHN0cm9rZS13aWR0aDoycHgsY29sb3I6IzMyNmNlNTtcbiAgICBjbGFzcyBuMSxuMixuMyxuNCBrOHM7XG4gICAgY2xhc3Mgem9uZUEsem9uZUIgY2x1c3RlcjtcbiIsIm1lcm1haWQiOiJ7XG4gIFwidGhlbWVcIjogXCJkZWZhdWx0XCJcbn0iLCJ1cGRhdGVFZGl0b3IiOmZhbHNlLCJhdXRvU3luYyI6dHJ1ZSwidXBkYXRlRGlhZ3JhbSI6dHJ1ZX0" _blank + +click n4 "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZ3JhcGggVEJcbiAgICBzdWJncmFwaCBcInpvbmVCXCJcbiAgICAgICAgbjMoTm9kZTMpXG4gICAgICAgIG40KE5vZGU0KVxuICAgIGVuZFxuICAgIHN1YmdyYXBoIFwiem9uZUFcIlxuICAgICAgICBuMShOb2RlMSlcbiAgICAgICAgbjIoTm9kZTIpXG4gICAgZW5kXG5cbiAgICBjbGFzc0RlZiBwbGFpbiBmaWxsOiNkZGQsc3Ryb2tlOiNmZmYsc3Ryb2tlLXdpZHRoOjRweCxjb2xvcjojMDAwO1xuICAgIGNsYXNzRGVmIGs4cyBmaWxsOiMzMjZjZTUsc3Ryb2tlOiNmZmYsc3Ryb2tlLXdpZHRoOjRweCxjb2xvcjojZmZmO1xuICAgIGNsYXNzRGVmIGNsdXN0ZXIgZmlsbDojZmZmLHN0cm9rZTojYmJiLHN0cm9rZS13aWR0aDoycHgsY29sb3I6IzMyNmNlNTtcbiAgICBjbGFzcyBuMSxuMixuMyxuNCBrOHM7XG4gICAgY2xhc3Mgem9uZUEsem9uZUIgY2x1c3RlcjtcbiIsIm1lcm1haWQiOiJ7XG4gIFwidGhlbWVcIjogXCJkZWZhdWx0XCJcbn0iLCJ1cGRhdGVFZGl0b3IiOmZhbHNlLCJhdXRvU3luYyI6dHJ1ZSwidXBkYXRlRGlhZ3JhbSI6dHJ1ZX0" _blank + +click n1 "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZ3JhcGggVEJcbiAgICBzdWJncmFwaCBcInpvbmVCXCJcbiAgICAgICAgbjMoTm9kZTMpXG4gICAgICAgIG40KE5vZGU0KVxuICAgIGVuZFxuICAgIHN1YmdyYXBoIFwiem9uZUFcIlxuICAgICAgICBuMShOb2RlMSlcbiAgICAgICAgbjIoTm9kZTIpXG4gICAgZW5kXG5cbiAgICBjbGFzc0RlZiBwbGFpbiBmaWxsOiNkZGQsc3Ryb2tlOiNmZmYsc3Ryb2tlLXdpZHRoOjRweCxjb2xvcjojMDAwO1xuICAgIGNsYXNzRGVmIGs4cyBmaWxsOiMzMjZjZTUsc3Ryb2tlOiNmZmYsc3Ryb2tlLXdpZHRoOjRweCxjb2xvcjojZmZmO1xuICAgIGNsYXNzRGVmIGNsdXN0ZXIgZmlsbDojZmZmLHN0cm9rZTojYmJiLHN0cm9rZS13aWR0aDoycHgsY29sb3I6IzMyNmNlNTtcbiAgICBjbGFzcyBuMSxuMixuMyxuNCBrOHM7XG4gICAgY2xhc3Mgem9uZUEsem9uZUIgY2x1c3RlcjtcbiIsIm1lcm1haWQiOiJ7XG4gIFwidGhlbWVcIjogXCJkZWZhdWx0XCJcbn0iLCJ1cGRhdGVFZGl0b3IiOmZhbHNlLCJhdXRvU3luYyI6dHJ1ZSwidXBkYXRlRGlhZ3JhbSI6dHJ1ZX0" _blank + +click n2 "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZ3JhcGggVEJcbiAgICBzdWJncmFwaCBcInpvbmVCXCJcbiAgICAgICAgbjMoTm9kZTMpXG4gICAgICAgIG40KE5vZGU0KVxuICAgIGVuZFxuICAgIHN1YmdyYXBoIFwiem9uZUFcIlxuICAgICAgICBuMShOb2RlMSlcbiAgICAgICAgbjIoTm9kZTIpXG4gICAgZW5kXG5cbiAgICBjbGFzc0RlZiBwbGFpbiBmaWxsOiNkZGQsc3Ryb2tlOiNmZmYsc3Ryb2tlLXdpZHRoOjRweCxjb2xvcjojMDAwO1xuICAgIGNsYXNzRGVmIGs4cyBmaWxsOiMzMjZjZTUsc3Ryb2tlOiNmZmYsc3Ryb2tlLXdpZHRoOjRweCxjb2xvcjojZmZmO1xuICAgIGNsYXNzRGVmIGNsdXN0ZXIgZmlsbDojZmZmLHN0cm9rZTojYmJiLHN0cm9rZS13aWR0aDoycHgsY29sb3I6IzMyNmNlNTtcbiAgICBjbGFzcyBuMSxuMixuMyxuNCBrOHM7XG4gICAgY2xhc3Mgem9uZUEsem9uZUIgY2x1c3RlcjtcbiIsIm1lcm1haWQiOiJ7XG4gIFwidGhlbWVcIjogXCJkZWZhdWx0XCJcbn0iLCJ1cGRhdGVFZGl0b3IiOmZhbHNlLCJhdXRvU3luYyI6dHJ1ZSwidXBkYXRlRGlhZ3JhbSI6dHJ1ZX0" _blank + +{{< /mermaid >}} + + +图 6. Pod 拓扑分布约束 + +代码块: + +``` +graph TB + subgraph "zoneB" + n3(Node3) + n4(Node4) + end + subgraph "zoneA" + n1(Node1) + n2(Node2) + end + + classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000; + classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff; + classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5; + class n1,n2,n3,n4 k8s; + class zoneA,zoneB cluster; +``` + + +### 示例 2 - Ingress + +图 7 显示的是 [Ingress 是什么](/zh/docs/concepts/services-networking/ingress/#what-is-ingress) +页面所出现的图表。 + +{{< mermaid >}} +graph LR; +client([客户端])-. Ingress 所管理的
负载均衡器 .->ingress[Ingress]; +ingress-->|路由规则|service[服务]; +subgraph cluster +ingress; +service-->pod1[Pod]; +service-->pod2[Pod]; +end +classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000; +classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff; +classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5; +class ingress,service,pod1,pod2 k8s; +class client plain; +class cluster cluster; + +click client "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZ3JhcGggIExSXG4gIGNsaWVudChbY2xpZW50XSktLiBJbmdyZXNzLW1hbmFnZWQgPGJyPiBsb2FkIGJhbGFuY2VyIC4tPmluZ3Jlc3NbSW5ncmVzc107XG4gIGluZ3Jlc3MtLT58cm91dGluZyBydWxlfHNlcnZpY2VbU2VydmljZV07XG4gIHN1YmdyYXBoIGNsdXN0ZXJcbiAgaW5ncmVzcztcbiAgc2VydmljZS0tPnBvZDFbUG9kXTtcbiAgc2VydmljZS0tPnBvZDJbUG9kXTtcbiAgZW5kXG4gIGNsYXNzRGVmIHBsYWluIGZpbGw6I2RkZCxzdHJva2U6I2ZmZixzdHJva2Utd2lkdGg6NHB4LGNvbG9yOiMwMDA7XG4gIGNsYXNzRGVmIGs4cyBmaWxsOiMzMjZjZTUsc3Ryb2tlOiNmZmYsc3Ryb2tlLXdpZHRoOjRweCxjb2xvcjojZmZmO1xuICBjbGFzc0RlZiBjbHVzdGVyIGZpbGw6I2ZmZixzdHJva2U6I2JiYixzdHJva2Utd2lkdGg6MnB4LGNvbG9yOiMzMjZjZTU7XG4gIGNsYXNzIGluZ3Jlc3Msc2VydmljZSxwb2QxLHBvZDIgazhzO1xuICBjbGFzcyBjbGllbnQgcGxhaW47XG4gIGNsYXNzIGNsdXN0ZXIgY2x1c3RlcjtcbiIsIm1lcm1haWQiOiJ7XG4gIFwidGhlbWVcIjogXCJkZWZhdWx0XCJcbn0iLCJ1cGRhdGVFZGl0b3IiOmZhbHNlLCJhdXRvU3luYyI6dHJ1ZSwidXBkYXRlRGlhZ3JhbSI6ZmFsc2V9" _blank + +click ingress "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZ3JhcGggIExSXG4gIGNsaWVudChbY2xpZW50XSktLiBJbmdyZXNzLW1hbmFnZWQgPGJyPiBsb2FkIGJhbGFuY2VyIC4tPmluZ3Jlc3NbSW5ncmVzc107XG4gIGluZ3Jlc3MtLT58cm91dGluZyBydWxlfHNlcnZpY2VbU2VydmljZV07XG4gIHN1YmdyYXBoIGNsdXN0ZXJcbiAgaW5ncmVzcztcbiAgc2VydmljZS0tPnBvZDFbUG9kXTtcbiAgc2VydmljZS0tPnBvZDJbUG9kXTtcbiAgZW5kXG4gIGNsYXNzRGVmIHBsYWluIGZpbGw6I2RkZCxzdHJva2U6I2ZmZixzdHJva2Utd2lkdGg6NHB4LGNvbG9yOiMwMDA7XG4gIGNsYXNzRGVmIGs4cyBmaWxsOiMzMjZjZTUsc3Ryb2tlOiNmZmYsc3Ryb2tlLXdpZHRoOjRweCxjb2xvcjojZmZmO1xuICBjbGFzc0RlZiBjbHVzdGVyIGZpbGw6I2ZmZixzdHJva2U6I2JiYixzdHJva2Utd2lkdGg6MnB4LGNvbG9yOiMzMjZjZTU7XG4gIGNsYXNzIGluZ3Jlc3Msc2VydmljZSxwb2QxLHBvZDIgazhzO1xuICBjbGFzcyBjbGllbnQgcGxhaW47XG4gIGNsYXNzIGNsdXN0ZXIgY2x1c3RlcjtcbiIsIm1lcm1haWQiOiJ7XG4gIFwidGhlbWVcIjogXCJkZWZhdWx0XCJcbn0iLCJ1cGRhdGVFZGl0b3IiOmZhbHNlLCJhdXRvU3luYyI6dHJ1ZSwidXBkYXRlRGlhZ3JhbSI6ZmFsc2V9" _blank + +click service "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZ3JhcGggIExSXG4gIGNsaWVudChbY2xpZW50XSktLiBJbmdyZXNzLW1hbmFnZWQgPGJyPiBsb2FkIGJhbGFuY2VyIC4tPmluZ3Jlc3NbSW5ncmVzc107XG4gIGluZ3Jlc3MtLT58cm91dGluZyBydWxlfHNlcnZpY2VbU2VydmljZV07XG4gIHN1YmdyYXBoIGNsdXN0ZXJcbiAgaW5ncmVzcztcbiAgc2VydmljZS0tPnBvZDFbUG9kXTtcbiAgc2VydmljZS0tPnBvZDJbUG9kXTtcbiAgZW5kXG4gIGNsYXNzRGVmIHBsYWluIGZpbGw6I2RkZCxzdHJva2U6I2ZmZixzdHJva2Utd2lkdGg6NHB4LGNvbG9yOiMwMDA7XG4gIGNsYXNzRGVmIGs4cyBmaWxsOiMzMjZjZTUsc3Ryb2tlOiNmZmYsc3Ryb2tlLXdpZHRoOjRweCxjb2xvcjojZmZmO1xuICBjbGFzc0RlZiBjbHVzdGVyIGZpbGw6I2ZmZixzdHJva2U6I2JiYixzdHJva2Utd2lkdGg6MnB4LGNvbG9yOiMzMjZjZTU7XG4gIGNsYXNzIGluZ3Jlc3Msc2VydmljZSxwb2QxLHBvZDIgazhzO1xuICBjbGFzcyBjbGllbnQgcGxhaW47XG4gIGNsYXNzIGNsdXN0ZXIgY2x1c3RlcjtcbiIsIm1lcm1haWQiOiJ7XG4gIFwidGhlbWVcIjogXCJkZWZhdWx0XCJcbn0iLCJ1cGRhdGVFZGl0b3IiOmZhbHNlLCJhdXRvU3luYyI6dHJ1ZSwidXBkYXRlRGlhZ3JhbSI6ZmFsc2V9" _blank + +click pod1 "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZ3JhcGggIExSXG4gIGNsaWVudChbY2xpZW50XSktLiBJbmdyZXNzLW1hbmFnZWQgPGJyPiBsb2FkIGJhbGFuY2VyIC4tPmluZ3Jlc3NbSW5ncmVzc107XG4gIGluZ3Jlc3MtLT58cm91dGluZyBydWxlfHNlcnZpY2VbU2VydmljZV07XG4gIHN1YmdyYXBoIGNsdXN0ZXJcbiAgaW5ncmVzcztcbiAgc2VydmljZS0tPnBvZDFbUG9kXTtcbiAgc2VydmljZS0tPnBvZDJbUG9kXTtcbiAgZW5kXG4gIGNsYXNzRGVmIHBsYWluIGZpbGw6I2RkZCxzdHJva2U6I2ZmZixzdHJva2Utd2lkdGg6NHB4LGNvbG9yOiMwMDA7XG4gIGNsYXNzRGVmIGs4cyBmaWxsOiMzMjZjZTUsc3Ryb2tlOiNmZmYsc3Ryb2tlLXdpZHRoOjRweCxjb2xvcjojZmZmO1xuICBjbGFzc0RlZiBjbHVzdGVyIGZpbGw6I2ZmZixzdHJva2U6I2JiYixzdHJva2Utd2lkdGg6MnB4LGNvbG9yOiMzMjZjZTU7XG4gIGNsYXNzIGluZ3Jlc3Msc2VydmljZSxwb2QxLHBvZDIgazhzO1xuICBjbGFzcyBjbGllbnQgcGxhaW47XG4gIGNsYXNzIGNsdXN0ZXIgY2x1c3RlcjtcbiIsIm1lcm1haWQiOiJ7XG4gIFwidGhlbWVcIjogXCJkZWZhdWx0XCJcbn0iLCJ1cGRhdGVFZGl0b3IiOmZhbHNlLCJhdXRvU3luYyI6dHJ1ZSwidXBkYXRlRGlhZ3JhbSI6ZmFsc2V9" _blank + +click pod2 "https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZ3JhcGggIExSXG4gIGNsaWVudChbY2xpZW50XSktLiBJbmdyZXNzLW1hbmFnZWQgPGJyPiBsb2FkIGJhbGFuY2VyIC4tPmluZ3Jlc3NbSW5ncmVzc107XG4gIGluZ3Jlc3MtLT58cm91dGluZyBydWxlfHNlcnZpY2VbU2VydmljZV07XG4gIHN1YmdyYXBoIGNsdXN0ZXJcbiAgaW5ncmVzcztcbiAgc2VydmljZS0tPnBvZDFbUG9kXTtcbiAgc2VydmljZS0tPnBvZDJbUG9kXTtcbiAgZW5kXG4gIGNsYXNzRGVmIHBsYWluIGZpbGw6I2RkZCxzdHJva2U6I2ZmZixzdHJva2Utd2lkdGg6NHB4LGNvbG9yOiMwMDA7XG4gIGNsYXNzRGVmIGs4cyBmaWxsOiMzMjZjZTUsc3Ryb2tlOiNmZmYsc3Ryb2tlLXdpZHRoOjRweCxjb2xvcjojZmZmO1xuICBjbGFzc0RlZiBjbHVzdGVyIGZpbGw6I2ZmZixzdHJva2U6I2JiYixzdHJva2Utd2lkdGg6MnB4LGNvbG9yOiMzMjZjZTU7XG4gIGNsYXNzIGluZ3Jlc3Msc2VydmljZSxwb2QxLHBvZDIgazhzO1xuICBjbGFzcyBjbGllbnQgcGxhaW47XG4gIGNsYXNzIGNsdXN0ZXIgY2x1c3RlcjtcbiIsIm1lcm1haWQiOiJ7XG4gIFwidGhlbWVcIjogXCJkZWZhdWx0XCJcbn0iLCJ1cGRhdGVFZGl0b3IiOmZhbHNlLCJhdXRvU3luYyI6dHJ1ZSwidXBkYXRlRGlhZ3JhbSI6ZmFsc2V9" _blank + + +{{< /mermaid >}} + + +图 7. Ingress + +代码块: + +```mermaid +graph LR; + client([客户端])-. Ingress 所管理的
负载均衡器 .->ingress[Ingress]; + ingress-->|路由规则|service[服务]; + subgraph cluster + ingress; + service-->pod1[Pod]; + service-->pod2[Pod]; + end + classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000; + classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff; + classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5; + class ingress,service,pod1,pod2 k8s; + class client plain; + class cluster cluster; +``` + + +### 示例 3 - K8s 系统流程 + +图 8 给出的是一个 Mermaid 时序图,展示启动容器时 K8s 组件间的控制流。 + +{{< figure src="/docs/images/diagram-guide-example-3.svg" alt="K8s system flow diagram" class="diagram-large" caption="Figure 8. K8s system flow diagram" link="https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiJSV7aW5pdDp7XCJ0aGVtZVwiOlwibmV1dHJhbFwifX0lJVxuc2VxdWVuY2VEaWFncmFtXG4gICAgYWN0b3IgbWVcbiAgICBwYXJ0aWNpcGFudCBhcGlTcnYgYXMgY29udHJvbCBwbGFuZTxicj48YnI-YXBpLXNlcnZlclxuICAgIHBhcnRpY2lwYW50IGV0Y2QgYXMgY29udHJvbCBwbGFuZTxicj48YnI-ZXRjZCBkYXRhc3RvcmVcbiAgICBwYXJ0aWNpcGFudCBjbnRybE1nciBhcyBjb250cm9sIHBsYW5lPGJyPjxicj5jb250cm9sbGVyPGJyPm1hbmFnZXJcbiAgICBwYXJ0aWNpcGFudCBzY2hlZCBhcyBjb250cm9sIHBsYW5lPGJyPjxicj5zY2hlZHVsZXJcbiAgICBwYXJ0aWNpcGFudCBrdWJlbGV0IGFzIG5vZGU8YnI-PGJyPmt1YmVsZXRcbiAgICBwYXJ0aWNpcGFudCBjb250YWluZXIgYXMgbm9kZTxicj48YnI-Y29udGFpbmVyPGJyPnJ1bnRpbWVcbiAgICBtZS0-PmFwaVNydjogMS4ga3ViZWN0bCBjcmVhdGUgLWYgcG9kLnlhbWxcbiAgICBhcGlTcnYtLT4-ZXRjZDogMi4gc2F2ZSBuZXcgc3RhdGVcbiAgICBjbnRybE1nci0-PmFwaVNydjogMy4gY2hlY2sgZm9yIGNoYW5nZXNcbiAgICBzY2hlZC0-PmFwaVNydjogNC4gd2F0Y2ggZm9yIHVuYXNzaWduZWQgcG9kcyhzKVxuICAgIGFwaVNydi0-PnNjaGVkOiA1LiBub3RpZnkgYWJvdXQgcG9kIHcgbm9kZW5hbWU9XCIgXCJcbiAgICBzY2hlZC0-PmFwaVNydjogNi4gYXNzaWduIHBvZCB0byBub2RlXG4gICAgYXBpU3J2LS0-PmV0Y2Q6IDcuIHNhdmUgbmV3IHN0YXRlXG4gICAga3ViZWxldC0-PmFwaVNydjogOC4gbG9vayBmb3IgbmV3bHkgYXNzaWduZWQgcG9kKHMpXG4gICAgYXBpU3J2LT4-a3ViZWxldDogOS4gYmluZCBwb2QgdG8gbm9kZVxuICAgIGt1YmVsZXQtPj5jb250YWluZXI6IDEwLiBzdGFydCBjb250YWluZXJcbiAgICBrdWJlbGV0LT4-YXBpU3J2OiAxMS4gdXBkYXRlIHBvZCBzdGF0dXNcbiAgICBhcGlTcnYtLT4-ZXRjZDogMTIuIHNhdmUgbmV3IHN0YXRlIiwibWVybWFpZCI6IntcbiAgXCJ0aGVtZVwiOiBcImRlZmF1bHRcIlxufSIsInVwZGF0ZUVkaXRvciI6ZmFsc2UsImF1dG9TeW5jIjp0cnVlLCJ1cGRhdGVEaWFncmFtIjp0cnVlfQ" >}} + + + +代码段: + +``` +%%{init:{"theme":"neutral"}}%% +sequenceDiagram + actor me + participant apiSrv as 控制面

api-server + participant etcd as 控制面

etcd 数据存储 + participant cntrlMgr as 控制面

控制器管理器 + participant sched as 控制面

调度器 + participant kubelet as 节点

kubelet + participant container as 节点

容器运行时 + me->>apiSrv: 1. kubectl create -f pod.yaml + apiSrv-->>etcd: 2. 保存新状态 + cntrlMgr->>apiSrv: 3. 检查变更 + sched->>apiSrv: 4. 监视未分派的 Pod(s) + apiSrv->>sched: 5. 通知 nodename=" " 的 Pod + sched->>apiSrv: 6. 指派 Pod 到节点 + apiSrv-->>etcd: 7. 保存新状态 + kubelet->>apiSrv: 8. 查询新指派的 Pod(s) + apiSrv->>kubelet: 9. 将 Pod 绑定到节点 + kubelet->>container: 10. 启动容器 + kubelet->>apiSrv: 11. 更新 Pod 状态 + apiSrv-->>etcd: 12. 保存新状态 +``` + + +## 如何设置图表样式 + + +你可以使用大家都熟悉的 CSS 术语来为一个或多个图表元素设置渲染样式。 +你可以在 Mermaid 代码中使用两种类型的语句来完成这一工作: + +* `classDef` 定义一类样式属性; +* `class` 指定 class 所适用的一种或多种元素。 + + +在[图 7](https://mermaid-js.github.io/mermaid-live-editor/edit/#eyJjb2RlIjoiZ3JhcGggIExSXG4gIGNsaWVudChbY2xpZW50XSktLiBJbmdyZXNzLW1hbmFnZWQgPGJyPiBsb2FkIGJhbGFuY2VyIC4tPmluZ3Jlc3NbSW5ncmVzc107XG4gIGluZ3Jlc3MtLT58cm91dGluZyBydWxlfHNlcnZpY2VbU2VydmljZV07XG4gIHN1YmdyYXBoIGNsdXN0ZXJcbiAgaW5ncmVzcztcbiAgc2VydmljZS0tPnBvZDFbUG9kXTtcbiAgc2VydmljZS0tPnBvZDJbUG9kXTtcbiAgZW5kXG4gIGNsYXNzRGVmIHBsYWluIGZpbGw6I2RkZCxzdHJva2U6I2ZmZixzdHJva2Utd2lkdGg6NHB4LGNvbG9yOiMwMDA7XG4gIGNsYXNzRGVmIGs4cyBmaWxsOiMzMjZjZTUsc3Ryb2tlOiNmZmYsc3Ryb2tlLXdpZHRoOjRweCxjb2xvcjojZmZmO1xuICBjbGFzc0RlZiBjbHVzdGVyIGZpbGw6I2ZmZixzdHJva2U6I2JiYixzdHJva2Utd2lkdGg6MnB4LGNvbG9yOiMzMjZjZTU7XG4gIGNsYXNzIGluZ3Jlc3Msc2VydmljZSxwb2QxLHBvZDIgazhzO1xuICBjbGFzcyBjbGllbnQgcGxhaW47XG4gIGNsYXNzIGNsdXN0ZXIgY2x1c3RlcjtcbiIsIm1lcm1haWQiOiJ7XG4gIFwidGhlbWVcIjogXCJkZWZhdWx0XCJcbn0iLCJ1cGRhdGVFZGl0b3IiOmZhbHNlLCJhdXRvU3luYyI6dHJ1ZSwidXBkYXRlRGlhZ3JhbSI6dHJ1ZX0) +中,你可以看到这两种示例。 + + +``` +classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff; // 定义 k8s 类的样式 +class ingress,service,pod1,pod2 k8s; // k8s 类会应用到 ingress, service, pod1 and pod2 这些元素之上 +``` + + +你可以在你的图表中包含一个或多个 `classDef` 和 `class` 语句。 +你也可以在你的图表中为 k8s 组件使用官方的 K8s `#326ce5` 十六进制颜色代码。 + +关于样式设置和类的更多信息,可参阅 +[Mermaid Styling and classes docs](https://mermaid-js.github.io/mermaid/#/flowchart?id=styling-and-classes)。 + + +## 如何使用标题 {#how-to-use-captions} + + +标题用来为图表提供简要的描述。标题或短描述都可以作为图表标题。 +标题不是用来替换你在文档中要提供的解释性文字。 +相反,它们是用来在文字与图表之间建立“语境连接”的。 + + +将一些文字和带标题的图表组合到一起,可以为你所想要向用户传递的信息提供一种更为精确的表达。 + +没有标题的话,用户就必须在图表前后的文字中来回阅读,从而了解其含义。 +这会让用户感觉到很沮丧。 + + +图 9 给出合适的标题所需要具备的三要素:图表、图表标题和图表引用。 + +{{< mermaid >}} +flowchart +A[图表本身

内嵌 Mermaid 或
SVG 图片文件] +B[图表标题

添加图表编号和
标题文字] +C[图表引用

在文字中用图表
编号引用图表] + + classDef box fill:#fff,stroke:#000,stroke-width:1px,color:#000; + class A,B,C box + +click A "https://mermaid-js.github.io/mermaid-live-editor/edit#eyJjb2RlIjoiZmxvd2NoYXJ0XG4gICAgQVtEaWFncmFtPGJyPjxicj5JbmxpbmUgTWVybWFpZCBvcjxicj5TVkcgaW1hZ2UgZmlsZXNdXG4gICAgQltEaWFncmFtIENhcHRpb248YnI-PGJyPkFkZCBGaWd1cmUgTnVtYmVyLiBhbmQ8YnI-Q2FwdGlvbiBUZXh0XVxuICAgIENbRGlhZ3JhbSBSZWZlcnJhbDxicj48YnI-UmVmZXJlbmVuY2UgRmlndXJlIE51bWJlcjxicj5pbiB0ZXh0XVxuXG4gICAgY2xhc3NEZWYgYm94IGZpbGw6I2ZmZixzdHJva2U6IzAwMCxzdHJva2Utd2lkdGg6MXB4LGNvbG9yOiMwMDA7XG4gICAgY2xhc3MgQSxCLEMgYm94IiwibWVybWFpZCI6IntcbiAgXCJ0aGVtZVwiOiBcImRlZmF1bHRcIlxufSIsInVwZGF0ZUVkaXRvciI6ZmFsc2UsImF1dG9TeW5jIjp0cnVlLCJ1cGRhdGVEaWFncmFtIjpmYWxzZX0" _blank + +click B "https://mermaid-js.github.io/mermaid-live-editor/edit#eyJjb2RlIjoiZmxvd2NoYXJ0XG4gICAgQVtEaWFncmFtPGJyPjxicj5JbmxpbmUgTWVybWFpZCBvcjxicj5TVkcgaW1hZ2UgZmlsZXNdXG4gICAgQltEaWFncmFtIENhcHRpb248YnI-PGJyPkFkZCBGaWd1cmUgTnVtYmVyLiBhbmQ8YnI-Q2FwdGlvbiBUZXh0XVxuICAgIENbRGlhZ3JhbSBSZWZlcnJhbDxicj48YnI-UmVmZXJlbmVuY2UgRmlndXJlIE51bWJlcjxicj5pbiB0ZXh0XVxuXG4gICAgY2xhc3NEZWYgYm94IGZpbGw6I2ZmZixzdHJva2U6IzAwMCxzdHJva2Utd2lkdGg6MXB4LGNvbG9yOiMwMDA7XG4gICAgY2xhc3MgQSxCLEMgYm94IiwibWVybWFpZCI6IntcbiAgXCJ0aGVtZVwiOiBcImRlZmF1bHRcIlxufSIsInVwZGF0ZUVkaXRvciI6ZmFsc2UsImF1dG9TeW5jIjp0cnVlLCJ1cGRhdGVEaWFncmFtIjpmYWxzZX0" _blank + +click C "https://mermaid-js.github.io/mermaid-live-editor/edit#eyJjb2RlIjoiZmxvd2NoYXJ0XG4gICAgQVtEaWFncmFtPGJyPjxicj5JbmxpbmUgTWVybWFpZCBvcjxicj5TVkcgaW1hZ2UgZmlsZXNdXG4gICAgQltEaWFncmFtIENhcHRpb248YnI-PGJyPkFkZCBGaWd1cmUgTnVtYmVyLiBhbmQ8YnI-Q2FwdGlvbiBUZXh0XVxuICAgIENbRGlhZ3JhbSBSZWZlcnJhbDxicj48YnI-UmVmZXJlbmVuY2UgRmlndXJlIE51bWJlcjxicj5pbiB0ZXh0XVxuXG4gICAgY2xhc3NEZWYgYm94IGZpbGw6I2ZmZixzdHJva2U6IzAwMCxzdHJva2Utd2lkdGg6MXB4LGNvbG9yOiMwMDA7XG4gICAgY2xhc3MgQSxCLEMgYm94IiwibWVybWFpZCI6IntcbiAgXCJ0aGVtZVwiOiBcImRlZmF1bHRcIlxufSIsInVwZGF0ZUVkaXRvciI6ZmFsc2UsImF1dG9TeW5jIjp0cnVlLCJ1cGRhdGVEaWFncmFtIjpmYWxzZX0" _blank + +{{< /mermaid >}} + + +图 9. 标题要素 + +{{< note >}} + +你应该总是为文档中的每个图表添加标题。 +{{< /note >}} + + +**图表本身** + +Mermaid+SVG 和外部工具方法都会生成 `.svg` 图片文件。 + +下面的 `{{}}` 短代码是针对定义在保存于 +`/images/docs/components-of-kubernetes.svg` 中的 `.svg` 图片文件的。 + +```none +{{}} +``` + + +你需要将 `src`、`alt`、`class` 和 `caption` 取值传递给 `{{}}` 短代码。 +你可以使用 `diagram-large`、`diagram-medium` 和 `diagram-small` 类来调整图表的尺寸。 + +{{< note >}} + +使用内嵌方法来创建的图表不使用 `{{}}` 短代码。 +Mermaid 代码定义该图表将如何在页面上渲染。 +{{< /note >}} + + +关于创建图表的不同方法,可参阅[创建图表的方法](#methods-for-creating-diagrams)。 + + +**图表标题** + +接下来,添加图表标题。 + +如果你使用 `.svg` 图片文件来定义你的图表,你就需要使用 `{{}}` +短代码的 `caption` 参数。 + + +```none +{{}} +``` + + +如果你使用内嵌的 Mermaid 代码来定义图表,则你需要使用 Markdown 文本来添加标题。 + +```none +图 4. Kubernetes 架构组件 +``` + + +添加图表标题时需要考虑的问题: + +* 使用 `{{}}` 短代码来为 Mermaid+SVG 和外部工具方法制作的图表添加标题。 +* 对于内嵌方法制作的图表,使用简单的 Markdown 文本来为其添加标题。 +* 在你的图表标题前面添加 `图 <编号>.`. 你必须使用 `图` 字样, + 并且编号必须对于文档页面中所有图表而言唯一。 + 在编号之后添加一个英文句号。 +* 将图表标题添加到 `图 <编号>.` 之后,并且在同一行。 + 你必须为图表标题添加英文句点作为其结束标志。尽量保持标题文字简短。 +* 图表标题要放在图表 __之后__。 + + +**图表引用** + +最后,你可以添加图表引用。图表引用位于你的文档正文中,并且应该出现在图表之前。 +这样,用户可以将你的文字与对应的图表关联起来。引用时所给的 `图 <编号>` +部分要与图表标题中对应部分一致。 + + +你要避免使用空间上的相对引用,例如 `..下面的图片..` 或者 `..下面的图形..`。 + + +```text +图 10 展示的是 Kubernetes 体系结构。其控制面 ... +``` + + +图表引用是可选的,在有些场合中,添加这类引用是不合适的。 +如果你不是很确定,可以在文字中添加图表引用,以判断是否看起来、读起来比较通顺。 +如果仍然不确定,可以使用图表引用。 + + +**完整全图** + +图 10 展示的是一个 Kubernetes 架构图表,其中包含了图表本身、图表标题和图表引用。 + +这里的 `{{}}` 短代码负责渲染图表,添加标题并包含可选的 `link` +参数,以便于你为图表提供超级链接。图表引用也被包含在段落中。 + +下面是针对此图表的 `{{}}` 短代码。 + + +``` +{{}} +``` + + +{{< figure src="/images/docs/components-of-kubernetes.svg" alt="运行在集群中的 Kubernetes Pod" class="diagram-large" caption="图 10. Kubernetes 架构." link="https://kubernetes.io/docs/concepts/overview/components/" >}} + + +## 提示 {#tips} + +* 总是使用在线编辑器来创建和编辑你的图表。 +* 总是使用 Hugo 本地和 Netlify 预览来检查图表在文档中的渲染效果。 +* 提供图表源代码指针,例如 URL、源代码位置或者标明代码时是说明的。 + +* 总是提供图表标题。 +* 在问题报告或 PR 中包含 `.svg` 或 `.png` 图片与/或 Mermaid 代码会很有帮助。 +* 对于 Mermaid+SVG 方法和外部工具方法而言,尽量使用 `.svg` 图片文件, + 因为这类文件在被放大之后仍能清晰地显示。 +* 对于 `.svg` 文件的最佳实践是将其加载到一个 SVG 编辑工具中,并使用 + “将文字转换为路径”功能完成转换。 + +* Mermaid 不支持额外的图表或艺术形式。 +* Hugo Mermaid 短代码在在线编辑器中无法显示。 +* 如果你想要在在线编辑器中更改图表,你 __必须__ 保存它以便为图表生成新的 URL。 +* 点击本节中的图表,你可以查看其源代码及其在在线编辑器中的渲染效果。 + +* 查看本页的源代码,`diagram-guide.md` 文件,可以将其作为示例。 +* 查阅 [Mermaid docs](https://mermaid-js.github.io/mermaid/#/) 以获得更多的解释和示例。 + + +最重要的一点,__保持图表简单__。 +这样做会节省你和其他贡献者的时间,同时也会方便新的以及有经验的用户阅读。 + From 26e080cc1fefc4bf7b64ff7067904ee8f0c8a0bd Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Sat, 26 Mar 2022 22:23:09 +0800 Subject: [PATCH 036/102] [zh] update parallel-processing-expansion.md Signed-off-by: xin.li --- content/zh/docs/tasks/job/parallel-processing-expansion.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/zh/docs/tasks/job/parallel-processing-expansion.md b/content/zh/docs/tasks/job/parallel-processing-expansion.md index 2f5a8e13c3..88240fc8a5 100644 --- a/content/zh/docs/tasks/job/parallel-processing-expansion.md +++ b/content/zh/docs/tasks/job/parallel-processing-expansion.md @@ -302,7 +302,7 @@ spec: spec: containers: - name: c - image: busybox + image: busybox:1.28 command: ["sh", "-c", "echo Processing URL {{ url }} && sleep 5"] restartPolicy: Never {% endfor %} From c6c9ab547ac31bd6da6a5fa68e329c5351393355 Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Sat, 26 Mar 2022 22:40:05 +0800 Subject: [PATCH 037/102] [zh] Update install-kubectl-linux.md Signed-off-by: xin.li --- .../zh/docs/tasks/tools/install-kubectl-linux.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/content/zh/docs/tasks/tools/install-kubectl-linux.md b/content/zh/docs/tasks/tools/install-kubectl-linux.md index e8750446b5..b64e4df578 100644 --- a/content/zh/docs/tasks/tools/install-kubectl-linux.md +++ b/content/zh/docs/tasks/tools/install-kubectl-linux.md @@ -98,7 +98,7 @@ The following methods exist for installing kubectl on Linux: 基于校验和文件,验证 kubectl 的可执行文件: ```bash - echo "$(}} 4. 执行测试,以保障你安装的版本是最新的: ```bash kubectl version --client ``` + + 或者使用如下命令来查看版本的详细信息: + ```cmd + kubectl version --client --output=yaml + ``` -Этот документ каталог связь между плоскостью управления (apiserver) и кластером Kubernetes. Цель состоит в том, чтобы позволить пользователям настраивать свою установку для усиления сетевой конфигурации, чтобы кластер мог работать в ненадежной сети (или на полностью общедоступных IP-адресах облачного провайдера). +Этот документ описывает связь между плоскостью управления (apiserver) и кластером Kubernetes. Цель состоит в том, чтобы позволить пользователям настраивать свою установку для усиления сетевой конфигурации, чтобы кластер мог работать в ненадежной сети (или на полностью общедоступных IP-адресах облачного провайдера). ## Связь между плоскостью управления и узлом -В Kubernetes имеется API шаблон "hub-and-spoke". Все используемые API из узлов (или которые запускают pod-ы) завершает apiserver. Ни один из других компонентов плоскости управления не предназначен для предоставления удаленных сервисов. Apiserver настроен на прослушивание удаленных подключений через безопасный порт HTTPS. (обычно 443) с одной или несколькими включенными формами [идентификации](/docs/reference/access-authn-authz/authentication/) клиена. +В Kubernetes имеется API шаблон «ступица и спица» (hub-and-spoke). Все используемые API из узлов (или которые запускают pod-ы) завершает apiserver. Ни один из других компонентов плоскости управления не предназначен для предоставления удаленных сервисов. Apiserver настроен на прослушивание удаленных подключений через безопасный порт HTTPS (обычно 443) с одной или несколькими включенными формами [аутентификации](/docs/reference/access-authn-authz/authentication/) клиента. -Должна быть включена одна или несколько форм [идентификации](/docs/reference/access-authn-authz/authorization/), особенно если разрешены [анонимные запросы](/docs/reference/access-authn-authz/authentication/#anonymous-requests) или [service account tokens](/docs/reference/access-authn-authz/authentication/#service-account-tokens). +Должна быть включена одна или несколько форм [авторизации](/docs/reference/access-authn-authz/authorization/), особенно, если разрешены [анонимные запросы](/docs/reference/access-authn-authz/authentication/#anonymous-requests) или [ServiceAccount токены](/docs/reference/access-authn-authz/authentication/#service-account-tokens). -Узлы должны быть снабжены общедоступным корневым сертификатом для кластера, чтобы они могли безопасно подключаться к apiserver-у вместе с действительными учетными данными клиента. Хороший подход заключается в том, что учетные данные клиента, предоставляемые kubelet, имеют форму клиентского сертификата. См. Информацию о загрузке Kubelet TLS [kubelet TLS bootstrapping](/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/) для автоматической подготовки клиентских сертификатов kubelet. +Узлы должны быть снабжены публичным корневым сертификатом для кластера, чтобы они могли безопасно подключаться к apiserver-у вместе с действительными учетными данными клиента. Хороший подход заключается в том, чтобы учетные данные клиента, предоставляемые kubelet-у, имели форму клиентского сертификата. См. Информацию о загрузке kubelet TLS [kubelet TLS bootstrapping](/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/) для автоматической подготовки клиентских сертификатов kubelet. -pod-ы, которые хотят подключиться к apiserver, могут сделать это безопасно, используя учетную запись службы, чтобы Kubernetes автоматически вводил общедоступный корневой сертификат и действительный токен-носитель в pod при его создании. -Служба `kubernetes` (в пространстве имен `default`) is настроен с виртуальным IP-адресом, который перенаправляет (через kube-proxy) к endpoint HTTPS apiserver-а. +Pod-ы, которые хотят подключиться к apiserver, могут сделать это безопасно, используя ServiceAccount, чтобы Kubernetes автоматически вводил общедоступный корневой сертификат и действительный токен-носитель в pod при его создании. +Служба `kubernetes` (в пространстве имен `default`) настроена с виртуальным IP-адресом, который перенаправляет (через kube-proxy) на HTTPS эндпоинт apiserver-а. Компоненты уровня управления также взаимодействуют с кластером apiserver-а через защищенный порт. @@ -33,7 +33,7 @@ pod-ы, которые хотят подключиться к apiserver, мог ## Узел к плоскости управления -Существуют две пути взаимодействия от плоскости управления (apiserver) к узлам. Первый - от apiserver-а до kubelet процесса, который выполняется на каждом узле кластера. Второй - от apiserver к любому узлу, pod-у или службе через промежуточную функциональность apiserver-а. +Существуют два пути связи плоскости управления (apiserver) с узлами. Первый - от apiserver-а до kubelet процесса, который выполняется на каждом узле кластера. Второй - от apiserver к любому узлу, pod-у или службе через промежуточную функциональность apiserver-а. ### apiserver в kubelet @@ -43,21 +43,21 @@ pod-ы, которые хотят подключиться к apiserver, мог * Прикрепление (через kubectl) к запущенным pod-ам. * Обеспечение функциональности переадресации портов kubelet. -Эти соединения заверщаются в kubelet в endpoint HTTPS. По умолчанию apiserver не проверяет сертификат обслуживания kubelet-ов, что делает соединение подверженным к атаке человек по середине (man-in-the-middle) и **unsafe** запущенных в ненадежных или общедоступных сетях. +Эти соединения завершаются на HTTPS эндпоинте kubelet-a. По умолчанию apiserver не проверяет сертификат обслуживания kubelet-ов, что делает соединение подверженным к атаке «человек посередине» (man-in-the-middle) и **небезопасным** к запуску в ненадежных и/или общедоступных сетях. -Для проверки этого соединения, используется флаг `--kubelet-certificate-authority` чтобы предоставить apiserver-у набор корневых (root) сертификатов для проверки сертификата обслуживания kubelet-ов. +Для проверки этого соединения используется флаг `--kubelet-certificate-authority` чтобы предоставить apiserver-у набор корневых (root) сертификатов для проверки сертификата обслуживания kubelet-ов. -Если это не возможно, используйте [SSH-тунелирование](#ssh-tunnels) между apiserver-ом и kubelet, если это необходимо во избежании подключения по ненадежной или общедоступной сети. +Если это не возможно, используйте [SSH-тунелирование](#ssh-tunnels) между apiserver-ом и kubelet, если это необходимо, чтобы избежать подключения по ненадежной или общедоступной сети. -Наконец, Должны быть включены [пудентификация или авторизация Kubelet](/docs/reference/command-line-tools-reference/kubelet-authentication-authorization/) для защиты kubelet API. +Наконец, должны быть включены [аутентификация или авторизация kubelet](/docs/reference/command-line-tools-reference/kubelet-authentication-authorization/) для защиты kubelet API. ### apiserver для узлов, pod-ов, и служб -Соединение с apiserver-ом к узлу, pod-у или службе по умолчанию осушествяляется по обычному HTTP-соединению и поэтому не проходят проверку подлиности и не шифрование. Они могут быть запущены по защищенному HTTPS-соединению, добавив префикс `https:` к имени узла, pod-а или службы в URL-адресе API, но они не будут проверять сертификат предоставленный HTTPS endpoint, также не будут предоставлять учетные данные клиента. Таким образом, хотя соединение будет зашифровано, оно не обеспечит никаких гарантий целостности. Эти соединения **are not currently safe** запущенных в ненадежных или общедоступных сетях. +Соединения с apiserver к узлу, поду или сервису по умолчанию осуществляются по-обычному HTTP-соединению и поэтому не аутентифицируются, и не шифруются. Они могут быть запущены по защищенному HTTPS-соединению, после добавления префикса `https:` к имени узла, пода или сервиса в URL-адресе API, но они не будут проверять сертификат предоставленный HTTPS эндпоинтом, как и не будут предоставлять учетные данные клиента. Таким образом, хотя соединение будет зашифровано, оно не обеспечит никаких гарантий целостности. Эти соединения **в настоящее время небезопасны** для запуска в ненадежных или общедоступных сетях. -### SSH-тунели +### SSH-туннели -Kubernetes поддерживает SSH-туннели для защиты плоскости управления узлов от путей связи. В этой конфигурации apiserver инициирует SSH-туннель для каждого узла в кластере (подключается к ssh-серверу, прослушивая порт 22) и передает весь трафикпредназначенный для kubelet, узлу, pod-у или службе через тунель. Этот тунель гарантирует, что трафик не выводиться за пределы сети, в которой работает узел. +Kubernetes поддерживает SSH-туннели для защиты плоскости управления узлов от путей связи. В этой конфигурации apiserver инициирует SSH-туннель для каждого узла в кластере (подключается к ssh-серверу, прослушивая порт 22) и передает весь трафик предназначенный для kubelet, узлу, pod-у или службе через туннель. Этот туннель гарантирует, что трафик не выводится за пределы сети, в которой работает узел. SSH-туннели в настоящее время устарели, поэтому вы не должны использовать их, если не знаете, что делаете. Служба подключения является заменой этого канала связи. @@ -65,6 +65,6 @@ SSH-туннели в настоящее время устарели, поэто {{< feature-state for_k8s_version="v1.18" state="beta" >}} -В качестве замены SSH-туннелям, служба подключения обеспечивает уровень полномочие TCP для плоскости управления кластерной связи. Служба подключения состоит из двух частей: сервер подключения в сети плоскости управления и агентов подключения в сети узлов. Агенты службы подключения инициируют подключения к серверу подключения и поддерживают сетевое подключение. После включения службы подключения, весь трафик с плоскости управления на узлы проходит через эти соединения. +В качестве замены SSH-туннелям, служба подключения обеспечивает уровень полномочия TCP для плоскости управления кластерной связи. Служба подключения состоит из двух частей: сервер подключения к сети плоскости управления и агентов подключения в сети узлов. Агенты службы подключения инициируют подключения к серверу подключения и поддерживают сетевое подключение. После включения службы подключения, весь трафик с плоскости управления на узлы проходит через эти соединения. -Следуйте инструкциям [Задача службы подключения](/docs/tasks/extend-kubernetes/setup-konnectivity/) чтобы настроить службу подключения в кластере. +Следуйте инструкциям [Задача службы подключения,](/docs/tasks/extend-kubernetes/setup-konnectivity/) чтобы настроить службу подключения в кластере. From 48dc63e27f5ef82b4f118f2bb55cc75fda1b787a Mon Sep 17 00:00:00 2001 From: Ilya Z Date: Sat, 26 Mar 2022 22:37:48 +0400 Subject: [PATCH 046/102] fix_some_typos --- .../docs/concepts/architecture/controller.md | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/content/ru/docs/concepts/architecture/controller.md b/content/ru/docs/concepts/architecture/controller.md index 3df6517fa4..e46fbb022b 100644 --- a/content/ru/docs/concepts/architecture/controller.md +++ b/content/ru/docs/concepts/architecture/controller.md @@ -10,8 +10,8 @@ weight: 30 Вот один из примеров контура управления: термостат в помещении. -Когда вы устанавливаете температуру, это говорит термостату о вашем *желаемом состоянии*. Фактическая температура в помещении - это -*текущее состояние*. Термостат действует так, чтобы приблизить текущее состояние к желаемому состоянию, путем включения или выключения оборудования. +Когда вы устанавливаете температуру, это говорит термостату о вашем *желаемом состоянии*. Фактическая температура в помещении - это +*текущее состояние*. Термостат действует так, чтобы приблизить текущее состояние к желаемому состоянию, путем включения или выключения оборудования. {{< glossary_definition term_id="controller" length="short">}} @@ -27,7 +27,7 @@ weight: 30 имеют поле спецификации, которое представляет желаемое состояние. Контроллер (ы) для этого ресурса несут ответственность за приближение текущего состояния к желаемому состоянию Контроллер может выполнить это действие сам; чаще всего в Kubernetes, -контроллер будет отправляет сообщения на +контроллер отправляет сообщения на {{< glossary_tooltip text="сервер API" term_id="kube-apiserver" >}} которые имеют полезные побочные эффекты. Пример этого вы можете увидеть ниже. @@ -40,7 +40,7 @@ weight: 30 Контроллер {{< glossary_tooltip term_id="job" >}} является примером встроенного контроллера Kubernetes. Встроенные контроллеры управляют состоянием, взаимодействуя с кластером сервера API. Задание - это ресурс Kubernetes, который запускает -{{< glossary_tooltip term_id="pod" >}}, или возможно несколько Pod-ов, которые выполняют задание и затем останавливаются. +{{< glossary_tooltip term_id="pod" >}}, или возможно несколько Pod-ов, выполняющих задачу и затем останавливающихся. (После [планирования](/docs/concepts/scheduling-eviction/), Pod объекты становятся частью желаемого состояния для kubelet). @@ -50,9 +50,9 @@ weight: 30 {{< glossary_tooltip text="плоскости управления" term_id="control-plane" >}} действуют на основе информации (имеются ли новые запланированные Pod-ы для запуска), и в итоге работа завершается. -После того, как вы создадите новое задание, желаемое состояние для этого задания будет завершено. Контроллер задания приближает текущее состояние этого задания к желаемому состоянию: создает Pod-ы, которые выполняют работу, которую вы хотели для этого задания, чтобы задание было ближе к завершению. +После того как вы создадите новое задание, желаемое состояние для этого задания будет завершено. Контроллер задания приближает текущее состояние этой задачи к желаемому состоянию: создает Pod-ы, выполняющие работу, которую вы хотели для этой задачи, чтобы задание было ближе к завершению. -Контроллеры также обровляют объекты которые их настраивают. +Контроллеры также обновляют объекты которые их настраивают. Например: как только работа выполнена для задания, контроллер задания обновляет этот объект задание, чтобы пометить его как `Завершенный`. (Это немного похоже на то, как некоторые термостаты выключают свет, чтобы указать, что теперь ваша комната имеет установленную вами температуру). @@ -66,20 +66,20 @@ weight: 30 Контроллеры, которые взаимодействуют с внешним состоянием, находят свое желаемое состояние с сервера API, а затем напрямую взаимодействуют с внешней системой, чтобы приблизить текущее состояние. -(На самом деле существует [контроллер](https://github.com/kubernetes/autoscaler/), который горизонтально маштабирует узлы в вашем кластере.) +(На самом деле существует [контроллер](https://github.com/kubernetes/autoscaler/), который горизонтально масштабирует узлы в вашем кластере.) Важным моментом здесь является то, что контроллер вносит некоторые изменения, чтобы вызвать желаемое состояние, а затем сообщает текущее состояние обратно на сервер API вашего кластера. Другие контуры управления могут наблюдать за этими отчетными данными и предпринимать собственные действия. -В примере с термостатом, если в помещении очень холодно, тогда другой контроллер может также включить обогреватель для защиты от замерзания. В кластерах Kubernetes, плоскость управления косвенно работает с инструментами управления IP-адресами,службами хранения данных, API облочных провайдеров и другими службами для релизации +В примере с термостатом, если в помещении очень холодно, тогда другой контроллер может также включить обогреватель для защиты от замерзания. В кластерах Kubernetes, плоскость управления косвенно работает с инструментами управления IP-адресами, службами хранения данных, API облачных провайдеров и другими службами для реализации [расширения Kubernetes](/docs/concepts/extend-kubernetes/). ## Желаемое против текущего состояния {#desired-vs-current} -Kubernetes использует систему вида cloud-native и способен справлятся с постоянными изменениями. +Kubernetes использует систему вида cloud-native и способен справляться с постоянными изменениями. -Ваш кластер может изменяться в любой по мере выполнения работы и контуры управления автоматически устранают сбой. Это означает, что потенциально Ваш кластер никогда не достигнет стабильного состояния. +Ваш кластер может изменяться в любой по мере выполнения работы и контуры управления автоматически устраняют сбой. Это означает, что потенциально Ваш кластер никогда не достигнет стабильного состояния. -Пока контроллеры вашего кластера работают и могут вносить полезные изменения, не имеет значения, является ли общее состояние стабильным или нет. +Пока контроллеры вашего кластера работают и могут вносить полезные изменения, не имеет значения, является ли общее состояние стабильным или нет. ## Дизайн @@ -90,7 +90,7 @@ Kubernetes использует систему вида cloud-native и спос {{< note >}} Существует несколько контроллеров, которые создают или обновляют один и тот же тип объекта. За кулисами контроллеры Kubernetes следят за тем, чтобы обращать внимание только на ресурсы, связанные с их контролирующим ресурсом. -Например, у вас могут быть развертывания и задания; они оба создают Pod-ы. Контроллер заданий не удаляет Pod-ы созданные вашим развертиыванием, потому что имеется информационные ({{< glossary_tooltip term_id="label" text="метки" >}}) +Например, у вас могут быть развертывания и задания; они оба создают Pod-ы. Контроллер заданий не удаляет Pod-ы созданные вашим развертыванием, потому что имеется информационные ({{< glossary_tooltip term_id="label" text="метки" >}}) которые могут быть использованы контроллерами тем самым показывая отличие Pod-ов. {{< /note >}} @@ -102,7 +102,7 @@ Kubernetes поставляется с набором встроенных ко Kubernetes позволяет вам запускать устойчивую плоскость управления, так что в случае отказа одного из встроенных контроллеров работу берет на себя другая часть плоскости управления. Вы можете найти контроллеры, которые работают вне плоскости управления, чтобы расширить Kubernetes. -Или, если вы хотите, можете написать новый контроллер самостоятельно. Вы можете запустить свой собственный контроллер виде наборов Pod-ов, +Или, если вы хотите, можете написать новый контроллер самостоятельно. Вы можете запустить свой собственный контроллер в виде наборов Pod-ов, или внешнее в Kubernetes. Что подойдет лучше всего, будет зависеть от того, что делает этот конкретный контроллер. From 510bd76dd7f7f55922aa8ec5b0f36a40ddbac18c Mon Sep 17 00:00:00 2001 From: Ilya Z Date: Sat, 26 Mar 2022 22:49:23 +0400 Subject: [PATCH 047/102] gc_typos --- .../architecture/garbage-collection.md | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/content/ru/docs/concepts/architecture/garbage-collection.md b/content/ru/docs/concepts/architecture/garbage-collection.md index f7ded8b44e..e94da8fc62 100644 --- a/content/ru/docs/concepts/architecture/garbage-collection.md +++ b/content/ru/docs/concepts/architecture/garbage-collection.md @@ -23,7 +23,7 @@ weight: 50 Многие объекты в Kubernetes ссылаются друг на друга через [*ссылки владельцев*](/docs/concepts/overview/working-with-objects/owners-dependents/). Ссылки владельцев сообщают плоскости управления какие объекты зависят от других. Kubernetes использует ссылки владельцев, чтобы предоставить плоскости управления и другим API -клиентам, возможность очистить связанные ресурсы передудалением объекта. В большинстве случаев, Kubernetes автоматический управляет ссылками владельцев. +клиентам, возможность очистить связанные ресурсы перед удалением объекта. В большинстве случаев, Kubernetes автоматический управляет ссылками владельцев. Владелец отличается от [меток и селекторов](/docs/concepts/overview/working-with-objects/labels/) которые также используют некоторые ресурсы. Например, рассмотрим @@ -36,15 +36,15 @@ Kubernetes использует ссылки владельцев, чтобы п {{< note >}} Ссылки на владельцев перекрестных пространств имен запрещены по дизайну. Зависимости пространства имен могут указывать на область действия кластера или владельцев пространства имен. -Владелец пространства имен **должен** быть в том же пространстве имен что и зависимости. -Если это не возможно, cсылка владельца считается отсутствующей и зависимый объект подлежит удалению, как только будет проверено отсутствие всех владельцев. +Владелец пространства имен **должен** быть в том же пространстве имен, что и зависимости. +Если это не возможно, ссылка владельца считается отсутствующей и зависимый объект подлежит удалению, как только будет проверено отсутствие всех владельцев. Зависимости области действия кластер может указывать только владельцев области действия кластера. В версии v1.20+, если зависимость с областью действия кластера указывает на пространство имен как владелец, тогда он рассматривается как имеющий неразрешимую ссылку на владельца и не может быть обработан сборщиком мусора. В версии v1.20+, если сборщик мусора обнаружит недопустимое перекрестное пространство имен `ownerReference`, -или зависящие от облости действия кластера `ownerReference` ссылка на тип пространства имен, предупреждающее событие с причиной `OwnerRefInvalidNamespace` и `involvedObject` сообщающеся о не действительной зависимости. +или зависящие от области действия кластера `ownerReference` ссылка на тип пространства имен, предупреждающее событие с причиной `OwnerRefInvalidNamespace` и `involvedObject` сообщающее о недействительной зависимости. Вы можете проверить наличие такого рода событий, выполнив `kubectl get events -A --field-selector=reason=OwnerRefInvalidNamespace`. {{< /note >}} @@ -52,22 +52,22 @@ Kubernetes использует ссылки владельцев, чтобы п Kubernetes проверяет и удаляет объекты, на которые больше нет ссылок владельцев, так же как и pod-ов, оставленных после удаления ReplicaSet. Когда Вы удаляете объект, вы можете контролировать автоматический ли Kubernetes удаляет зависимые объекты автоматически в процессе вызова *каскадного удаления*. Существует два типа каскадного удаления, а именно: - * Каскадное удалени Foreground + * Каскадное удаление Foreground * Каскадное удаление Background Вы так же можете управлять как и когда сборщик мусора удаляет ресурсы, на которые ссылаются владельцы с помощью Kubernetes {{}}. -### Каскадное удалени Foreground {#foreground-deletion} +### Каскадное удаление Foreground {#foreground-deletion} -В Каскадном удалени Foreground, объект владельца, который вы удаляете, сначало переходить в состояние *в процессе удаления*. В этом состоянии с объектом-владельцем происходить следующее: +В Каскадном удалении Foreground, объект владельца, который вы удаляете, сначала переходить в состояние *в процессе удаления*. В этом состоянии с объектом-владельцем происходить следующее: * Сервер Kubernetes API устанавливает полю объекта `metadata.deletionTimestamp` время, когда объект был помечен для удаления. * Сервер Kubernetes API так же устанавливает метку `metadata.finalizers`для поля `foregroundDeletion`. - * Объект остается видимым блогодоря Kubernetes API пока процесс удаления не завершиться + * Объект остается видимым благодаря Kubernetes API пока процесс удаления не завершиться -После того, как владелец объекта переходит в состояние прогресса удаления, контроллер удаляет зависимые объекты. После удаления всех зависимых объектов, контроллер удаляет объект владельца. На этом этапе, объект больше не отображается в Kubernetes API. +После того как владелец объекта переходит в состояние прогресса удаления, контроллер удаляет зависимые объекты. После удаления всех зависимых объектов, контроллер удаляет объект владельца. На этом этапе, объект больше не отображается в Kubernetes API. Во время каскадного удаления foreground, единственным зависимым, которые блокируют удаления владельца, являются те, у кого имеется поле `ownerReference.blockOwnerDeletion=true`. Чтобы узнать больше. Смотрите [Использование каскадного удаления foreground](/docs/tasks/administer-cluster/use-cascading-deletion/#use-foreground-cascading-deletion). @@ -80,16 +80,16 @@ Kubernetes проверяет и удаляет объекты, на котор ### Осиротевшие зависимости -Когда Kubernetes удаляет владельца объекта, оставшиеся зависимости называются *осиротевшыми* объектами. По умолчанию, Kubernetes удаляет зависимые объекты. Чтобы узнать, как переопределить это повидение смотрите [Удаление объектов владельца и осиротевших зависимостей](/docs/tasks/administer-cluster/use-cascading-deletion/#set-orphan-deletion-policy). +Когда Kubernetes удаляет владельца объекта, оставшиеся зависимости называются *осиротевшими* объектами. По умолчанию, Kubernetes удаляет зависимые объекты. Чтобы узнать, как переопределить это поведение смотрите [Удаление объектов владельца и осиротевших зависимостей](/docs/tasks/administer-cluster/use-cascading-deletion/#set-orphan-deletion-policy). -## Сбор мусора из неиспользуемых контейнеров и изобробразов {#containers-images} +## Сбор мусора из неиспользуемых контейнеров и изображений {#containers-images} {{}} выполняет сбор мусора для неиспользуемых образов каждые пять минут и для неиспользуемых контейнеров каждую минуту. Вам следует избегать использования внешних инструментов для сборки мусора, так как они могут нарушить поведение kubelet и удалить контейнеры, которые должны существовать. -Чтобы настроить параметры для сборшика мусора для неиспользуемого контейнера и сборки мусора образа, подстройте +Чтобы настроить параметры для сборщика мусора для неиспользуемого контейнера и сборки мусора образа, подстройте kubelet использую [конфигурационный файл](/docs/tasks/administer-cluster/kubelet-config-file/) -и измените параметры, связанные со сборшиком мусора используя тип ресурса +и измените параметры, связанные со сборщиком мусора используя тип ресурса [`KubeletConfiguration`](/docs/reference/config-api/kubelet-config.v1beta1/#kubelet-config-k8s-io-v1beta1-KubeletConfiguration). ### Жизненный цикл контейнерных образов Container image lifecycle @@ -99,19 +99,19 @@ Kubernetes управляет жизненным циклом всех обра * `HighThresholdPercent` * `LowThresholdPercent` -Использование диска выше настроенного значения `HighThresholdPercent` запускает сборку мусора, которая удаляет образы в порядке основанном на последнем использовании, начиная с самого старого. kubelet удлаяет образы до тех пор, пока использование диска не достигнет значения `LowThresholdPercent`. +Использование диска выше настроенного значения `HighThresholdPercent` запускает сборку мусора, которая удаляет образы в порядке основанном на последнем использовании, начиная с самого старого. Kubelet удаляет образы до тех пор, пока использование диска не достигнет значения `LowThresholdPercent`. ### Сборщик мусора контейнерных образов {#container-image-garbage-collection} -kubelet собирает не используемые контейнеры на основе следующих переменных, которые вы можете определить: +Kubelet собирает не используемые контейнеры на основе следующих переменных, которые вы можете определить: * `MinAge`: минимальный возраст, при котором kubelet может начать собирать мусор контейнеров. Отключить, установив значение `0`. - * `MaxPerPodContainer`: максимальное количество некативныз контейнеров, которое может быть у каджой пары Pod-ов. Отключить, установив значение меньше чем `0`. + * `MaxPerPodContainer`: максимальное количество неактивных контейнеров, которое может быть у каждой пары Pod-ов. Отключить, установив значение меньше чем `0`. * `MaxContainers`: максимальное количество не используемых контейнеров, которые могут быть в кластере. Отключить, установив значение меньше чем `0`. В дополнение к этим переменным, kubelet собирает неопознанные и удаленные контейнеры, обычно начиная с самого старого. -`MaxPerPodContainer` и `MaxContainer` могут потенциально конфликтовать друг с другом в ситуациях, когда требуется максимальное количество контейнеров в Pod-е (`MaxPerPodContainer`) выйдет за пределы допустимого общего количества глобальных не используемых контейнеров (`MaxContainers`). В этой ситуации kubelet регулирует `MaxPodPerContainer` для устранения конфликта. наихудшим сценарием было бы понизить `MaxPerPodContainer` да `1` и изгнать самые старые контейнеры. +`MaxPerPodContainer` и `MaxContainer` могут потенциально конфликтовать друг с другом в ситуациях, когда требуется максимальное количество контейнеров в Pod-е (`MaxPerPodContainer`) выйдет за пределы допустимого общего количества глобальных не используемых контейнеров (`MaxContainers`). В этой ситуации kubelet регулирует `MaxPodPerContainer` для устранения конфликта. Наихудшим сценарием было бы понизить `MaxPerPodContainer` да `1` и изгнать самые старые контейнеры. Кроме того, владельцы контейнеров в pod-е могут быть удалены, как только они становятся старше чем `MinAge`. {{}} @@ -120,7 +120,7 @@ Kubelet собирает мусор только у контейнеров, ко ## Настройка сборщик мусора {#configuring-gc} -Вы можете настроить сборку мусора ресурсов, настроив параметры, специфичные для контроллеров, управляющих этими ресурсами. В последующих страницах показанно, как настроить сборку мусора: +Вы можете настроить сборку мусора ресурсов, настроив параметры, специфичные для контроллеров, управляющих этими ресурсами. В последующих страницах показано, как настроить сборку мусора: * [Настройка каскадного удаления объектов Kubernetes](/docs/tasks/administer-cluster/use-cascading-deletion/) * [Настройка очистки завершенных заданий](/docs/concepts/workloads/controllers/ttlafterfinished/) From 232c79f4e4e2646064c1239a18e934b23677eb9f Mon Sep 17 00:00:00 2001 From: Ilya Z Date: Sat, 26 Mar 2022 23:03:46 +0400 Subject: [PATCH 048/102] fix_some_typos --- .../ru/docs/concepts/architecture/nodes.md | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/content/ru/docs/concepts/architecture/nodes.md b/content/ru/docs/concepts/architecture/nodes.md index 075c3140f5..613155f012 100644 --- a/content/ru/docs/concepts/architecture/nodes.md +++ b/content/ru/docs/concepts/architecture/nodes.md @@ -32,7 +32,7 @@ Kubernetes запускает ваши приложения, помещая ко 1. Kubelet на узле саморегистрируется в плоскости управления 2. Вы или другой пользователь вручную добавляете объект Узла -После того, как вы создадите объект Узла или kubelet на узле самозарегистируется, +После того как вы создадите объект Узла или kubelet на узле самозарегистируется, плоскость управления проверяет, является ли новый объект Узла валидным (правильным). Например, если вы попробуете создать Узел при помощи следующего JSON манифеста: @@ -50,9 +50,9 @@ Kubernetes запускает ваши приложения, помещая ко ``` Kubernetes создает внутри себя объект Узла (представление). Kubernetes проверяет, -что kubelet зарегистрировался на API сервере, который совпадает с значением поля `metadata.name` Узла. +что kubelet зарегистрировался на API сервере, который совпадает со значением поля `metadata.name` Узла. Если узел здоров (если все необходимые сервисы запущены), -он имеет право на запуск Пода. В противном случае, этот узел игнорируется для любой активности кластера +он имеет право на запуск Пода. В противном случае этот узел игнорируется для любой активности кластера до тех пор, пока он не станет здоровым. {{< note >}} @@ -62,13 +62,13 @@ Kubernetes сохраняет объект для невалидного Узл остановить проверку доступности узла. {{< /note >}} -Имя объекта Узла дожно быть валидным +Имя объекта Узла должно быть валидным [именем поддомена DNS](/ru/docs/concepts/overview/working-with-objects/names#имена-поддоменов-dns). ### Саморегистрация Узлов Когда kubelet флаг `--register-node` имеет значение _true_ (по умолчанию), то kubelet будет пытаться -зарегистрировать себя на API сервере. Это наиболее предпочтительная модель, используемая большиством дистрибутивов. +зарегистрировать себя на API сервере. Это наиболее предпочтительная модель, используемая большинством дистрибутивов. Для саморегистрации kubelet запускается со следующими опциями: @@ -94,16 +94,16 @@ kubelet'ы имеют право только создавать/изменят Когда вы хотите создать объекты Узла вручную, установите kubelet флаг `--register-node=false`. Вы можете изменять объекты Узла независимо от настройки `--register-node`. -Например, вы можете установить метки на существующем Узле или пометить его неназначаемым. +Например, вы можете установить метки на существующем Узле или пометить его не назначаемым. Вы можете использовать метки на Узлах в сочетании с селекторами узла на Подах для управления планированием. -Например, вы можете ограничить Под иметь право на запуск только на группе доступных узлов. +Например, вы можете ограничить Под, иметь право на запуск только на группе доступных узлов. -Маркировка узла как неназначаемого предотвращает размещение планировщиком новых подов на этом Узле, +Маркировка узла как не назначаемого предотвращает размещение планировщиком новых подов на этом Узле, но не влияет на существующие Поды на Узле. Это полезно в качестве подготовительного шага перед перезагрузкой узла или другим обслуживанием. -Чтобы отметить Узел неназначемым, выполните: +Чтобы отметить Узел не назначаемым, выполните: ```shell kubectl cordon $NODENAME @@ -111,7 +111,7 @@ kubectl cordon $NODENAME {{< note >}} Поды, являющиеся частью {{< glossary_tooltip term_id="daemonset" >}} допускают -запуск на неназначаемом Узле. DaemonSets обычно обеспечивает локальные сервисы узла, +запуск на не назначаемом Узле. DaemonSets обычно обеспечивает локальные сервисы узла, которые должны запускаться на Узле, даже если узел вытесняется для запуска приложений. {{< /note >}} @@ -157,7 +157,7 @@ kubectl describe node {{< note >}} Если вы используете инструменты командной строки для вывода сведений об блокированном узле, то Условие включает `SchedulingDisabled`. `SchedulingDisabled` не является Условием в Kubernetes API; -вместо этого блокированные узлы помечены как Неназначемые в их спецификации. +вместо этого блокированные узлы помечены как Не назначаемые в их спецификации. {{< /note >}} Состояние узла представлено в виде JSON объекта. Например, следующая структура описывает здоровый узел: @@ -203,8 +203,8 @@ kubectl describe node Описывает ресурсы, доступные на узле: CPU, память и максимальное количество подов, которые могут быть запланированы на узле. -Поля в блоке capasity указывают общее количество ресурсов, которые есть на Узле. -Блок allocatable указывает количество ресурсовна Узле, +Поля в блоке capacity указывают общее количество ресурсов, которые есть на Узле. +Блок allocatable указывает количество ресурсов на Узле, которые доступны для использования обычными Подами. Вы можете прочитать больше о емкости и выделяемых ресурсах, изучая, как [зарезервировать вычислительные ресурсы](/docs/tasks/administer-cluster/reserve-compute-resources/#node-allocatable) на Узле. @@ -212,7 +212,7 @@ kubectl describe node ### Информация (Info) Описывает общую информацию об узле, такую как версия ядра, версия Kubernetes (версии kubelet и kube-proxy), версия Docker (если используется) и название ОС. -Эта информация соберается Kubelet'ом на узле. +Эта информация собирается Kubelet'ом на узле. ### Контроллер узла @@ -247,16 +247,16 @@ ConditionUnknown, когда узел становится недоступны [Lease объект](/docs/reference/generated/kubernetes-api/{{< latest-version >}}/#lease-v1-coordination-k8s-io). Каждый узел имеет связанный с ним Lease объект в `kube-node-lease` {{< glossary_tooltip term_id="namespace" text="namespace">}}. -Lease - это легковестный ресурс, который улучшает производительность +Lease - это легковесный ресурс, который улучшает производительность сердцебиений узла при масштабировании кластера. -Kubelet отвечает за создание и обновление `NodeStatus` и Lease объекта. +Kubelet отвечает за создание и обновление `NodeStatus` и Lease объекта. - Kubelet обновляет `NodeStatus` либо когда происходит изменение статуса, - либо если в течение настронного интервала обновления не было. По умолчанию + либо если в течение настроенного интервала обновления не было. По умолчанию интервал для обновлений `NodeStatus` составляет 5 минут (намного больше, чем 40-секундный стандартный таймаут для недоступных узлов). -- Kubelet созадет и затем обновляет свой Lease объект каждый 10 секунд +- Kubelet создает и затем обновляет свой Lease объект каждый 10 секунд (интервал обновления по умолчанию). Lease обновления происходят независимо от `NodeStatus` обновлений. Если обновление Lease завершается неудачно, kubelet повторяет попытку с экспоненциальным откатом, начинающимся с 200 миллисекунд и ограниченным 7 секундами. @@ -265,7 +265,7 @@ Kubelet отвечает за создание и обновление `NodeStat В большинстве случаев контроллер узла ограничивает скорость выселения до `--node-eviction-rate` (по умолчанию 0,1) в секунду, что означает, -что он не выселяет поды с узлов быстрее чем c 1 узела в 10 секунд. +что он не выселяет поды с узлов быстрее чем с одного узла в 10 секунд. Поведение выселения узла изменяется, когда узел в текущей зоне доступности становится нездоровым. Контроллер узла проверяет, какой процент узлов в зоне @@ -288,26 +288,26 @@ Kubelet отвечает за создание и обновление `NodeStat выселяет поды с нормальной скоростью `--node-eviction-rate`. Крайний случай - когда все зоны полностью нездоровы (т.е. в кластере нет здоровых узлов). В таком случае контроллер узла предполагает, что существует некоторая проблема с подключением к мастеру, -и останавеливает все выселения, пока какое-нибудь подключение не будет восстановлено. +и останавливает все выселения, пока какое-нибудь подключение не будет восстановлено. Контроллер узла также отвечает за выселение подов, запущенных на узлах с `NoExecute` ограничениями, за исключением тех подов, которые сопротивляются этим ограничениям. Контроллер узла так же добавляет {{< glossary_tooltip text="ограничения" term_id="taint" >}} -соотвествующие проблемам узла, таким как узел недоступен или не готов. Это означает, +соответствующие проблемам узла, таким как узел недоступен или не готов. Это означает, что планировщик не будет размещать поды на нездоровых узлах. {{< caution >}} -`kubectl cordon` помечает узел как 'неназначемый', что имеет побочный эфект от контроллера сервисов, +`kubectl cordon` помечает узел как 'не назначаемый', что имеет побочный эффект от контроллера сервисов, удаляющего узел из любых списков целей LoadBalancer узла, на которые он ранее имел право, -эффектино убирая входящий трафик балансировщика нагрузки с блокированного узла(ов). +эффективно убирая входящий трафик балансировщика нагрузки с блокированного узла(ов). {{< /caution >}} ### Емкость узла Объекты узла отслеживают информацию о емкости ресурсов узла (например, объем доступной памяти и количество CPU). -Узлы, которые [самостоятельно зарегистировались](#саморегистрация-узлов) сообщают -о свое емкости во время регистрации. Если вы [вручную](#ручное-администрирование-узла) +Узлы, которые [самостоятельно зарегистрировались](#саморегистрация-узлов), сообщают +о своей емкости во время регистрации. Если вы [вручную](#ручное-администрирование-узла) добавляете узел, то вам нужно задать информацию о емкости узла при его добавлении. {{< glossary_tooltip text="Планировщик" term_id="kube-scheduler" >}} Kubernetes гарантирует, @@ -318,7 +318,7 @@ Kubelet отвечает за создание и обновление `NodeStat а также исключает любые процессы, запущенные вне контроля kubelet. {{< note >}} -Если вы явно хотите зарезервировать ресурсы для процессов, не связанныз с Подами, смотрите раздел +Если вы явно хотите зарезервировать ресурсы для процессов, не связанных с Подами, смотрите раздел [зарезервировать ресурсы для системных демонов](/docs/tasks/administer-cluster/reserve-compute-resources/#system-reserved). {{< /note >}} @@ -339,4 +339,4 @@ Kubelet отвечает за создание и обновление `NodeStat * Подробнее про [Узлы](https://git.k8s.io/community/contributors/design-proposals/architecture/architecture.md#the-kubernetes-node) of the architecture design document. * Подробнее про [ограничения и допуски](/docs/concepts/configuration/taint-and-toleration/). -* Подробнее про [автомаштабирование кластера](/docs/tasks/administer-cluster/cluster-management/#cluster-autoscaling). +* Подробнее про [авто масштабирование кластера](/docs/tasks/administer-cluster/cluster-management/#cluster-autoscaling). From 0c259797db186ad73214f96b036614b6c2745337 Mon Sep 17 00:00:00 2001 From: Ilya Z Date: Sat, 26 Mar 2022 23:18:08 +0400 Subject: [PATCH 049/102] cluster_admin_typos --- .../concepts/cluster-administration/_index.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/content/ru/docs/concepts/cluster-administration/_index.md b/content/ru/docs/concepts/cluster-administration/_index.md index b596e111f3..77f610bf18 100644 --- a/content/ru/docs/concepts/cluster-administration/_index.md +++ b/content/ru/docs/concepts/cluster-administration/_index.md @@ -11,7 +11,7 @@ no_list: true --- -Обзор администрирования кластера предназначен для всех, кто создает или администрирует кластер Kubernetes. Это предполагает некоторое знакомство с основными [концепциями] (/docs/concepts/) Kubernetes. +Обзор администрирования кластера предназначен для всех, кто создает или администрирует кластер Kubernetes. Это предполагает некоторое знакомство с основными [концепциями](/docs/concepts/) Kubernetes. @@ -19,19 +19,19 @@ no_list: true См. Руководства в разделе [настройка](/docs/setup/) для получения примеров того, как планировать, устанавливать и настраивать кластеры Kubernetes. Решения, перечисленные в этой статье, называются *distros*. - {{< note >}} + {{< note >}} не все дистрибутивы активно поддерживаются. Выбирайте дистрибутивы, протестированные с последней версией Kubernetes. {{< /note >}} Прежде чем выбрать руководство, вот некоторые соображения: - - Вы хотите опробовать Kubernetes на вашем компьюторе или собрать многоузловой кластер высокой доступности? Выбирайте дистрибутивы, наиболее подходящие для ваших нужд. - - будете ли вы использовать **размещенный кластер Kubernetes**, такой как [Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine/) или **разместите собственный кластер**? - - Будет ли ваш кластер **в помещений** или **в облаке (IaaS)**? Kubernetes не поддерживает напрямую гибридные кластеры. Вместо этого вы можете настроить несколько кластеров. - - **Если вы будете настроаивать Kubernetes в помещений (локально)**, подумайте, какая [сетевая модель](/docs/concepts/cluster-administration/networking/) подходит лучше всего. - - Будете ли вы запускать Kubernetes на **оборудований "bare metal"** или на **вирутальных машинах (VMs)**? - - Вы хотите **запустить кластер** или планируете **активно разворачивать код проекта Kubernetes**? В последнем случае выберите активно разрабатываемый дистрибутив. Некоторые дистрибутивы используют только двоичные выпуски, но предлагают болле широкий выбор. - - Ознакомьтесь с [компонентами](/docs/concepts/overview/components/) необходивые для запуска кластера. + - Вы хотите опробовать Kubernetes на вашем компьютере или собрать много узловой кластер высокой доступности? Выбирайте дистрибутивы, наиболее подходящие для ваших нужд. + - Будете ли вы использовать **размещенный кластер Kubernetes**, такой, как [Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine/) или **разместите собственный кластер**? + - Будет ли ваш кластер **в помещении** или **в облаке (IaaS)**? Kubernetes не поддерживает напрямую гибридные кластеры. Вместо этого вы можете настроить несколько кластеров. + - **Если вы будете настраивать Kubernetes в помещении (локально)**, подумайте, какая [сетевая модель](/docs/concepts/cluster-administration/networking/) подходит лучше всего. + - Будете ли вы запускать Kubernetes на **оборудований "bare metal"** или на **виртуальных машинах (VMs)**? + - Вы хотите **запустить кластер** или планируете **активно разворачивать код проекта Kubernetes**? В последнем случае выберите активно разрабатываемый дистрибутив. Некоторые дистрибутивы используют только двоичные выпуски, но предлагают более широкий выбор. + - Ознакомьтесь с [компонентами](/docs/concepts/overview/components/) необходимые для запуска кластера. ## Управление кластером @@ -54,7 +54,7 @@ no_list: true * [Использование контроллеров допуска](/docs/reference/access-authn-authz/admission-controllers/) explains plug-ins which intercepts requests to the Kubernetes API server after authentication and authorization. -* [Использование Sysctls в кластере Kubernetes](/docs/tasks/administer-cluster/sysctl-cluster/) описывает администратору, как использовать sysctlинструмент командной строки для установки параметров ядра. +* [Использование Sysctls в кластере Kubernetes](/docs/tasks/administer-cluster/sysctl-cluster/) описывает администратору, как использовать sysctl инструмент командной строки для установки параметров ядра. * [Аудит](/docs/tasks/debug-application-cluster/audit/) описывает, как взаимодействовать с журналами аудита Kubernetes. From 026b8773ffc530ab387f7a2117287384d110be92 Mon Sep 17 00:00:00 2001 From: Ilya Z Date: Sat, 26 Mar 2022 23:40:25 +0400 Subject: [PATCH 050/102] addons_typos --- .../concepts/cluster-administration/addons.md | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/content/ru/docs/concepts/cluster-administration/addons.md b/content/ru/docs/concepts/cluster-administration/addons.md index e86d485949..7e93ef82b2 100644 --- a/content/ru/docs/concepts/cluster-administration/addons.md +++ b/content/ru/docs/concepts/cluster-administration/addons.md @@ -13,33 +13,33 @@ content_type: concept -## Сеть и сетевыя политика +## Сеть и сетевая политика * [ACI](https://www.github.com/noironetworks/aci-containers) обеспечивает интегрированную сеть контейнеров и сетевую безопасность с помощью Cisco ACI. * [Antrea](https://antrea.io/) работает на уровне 3, обеспечивая сетевые службы и службы безопасности для Kubernetes, используя Open vSwitch в качестве уровня сетевых данных. * [Calico](https://docs.projectcalico.org/latest/introduction/) Calico поддерживает гибкий набор сетевых опций, поэтому вы можете выбрать наиболее эффективный вариант для вашей ситуации, включая сети без оверлея и оверлейные сети, с или без BGP. Calico использует тот же механизм для обеспечения соблюдения сетевой политики для хостов, модулей и (при использовании Istio и Envoy) приложений на уровне сервисной сети (mesh layer). -* [Canal](https://github.com/tigera/canal/tree/master/k8s-install) объединяет Flannel и Calico, обеспечивая сеть и сетевую политик. +* [Canal](https://github.com/tigera/canal/tree/master/k8s-install) объединяет Flannel и Calico, обеспечивая сеть и сетевую политику. * [Cilium](https://github.com/cilium/cilium) - это плагин сети L3 и сетевой политики, который может прозрачно применять политики HTTP/API/L7. Поддерживаются как режим маршрутизации, так и режим наложения/инкапсуляции, и он может работать поверх других подключаемых модулей CNI. * [CNI-Genie](https://github.com/Huawei-PaaS/CNI-Genie) позволяет Kubernetes легко подключаться к выбору плагинов CNI, таких как Calico, Canal, Flannel, Romana или Weave. -* [Contrail](https://www.juniper.net/us/en/products-services/sdn/contrail/contrail-networking/), основан на [Tungsten Fabric](https://tungsten.io), представляет собой платформу для виртуализации мультиоблачных сетей с открытым исходным кодом и управления политиками. Contrail и Tungsten Fabric are интегрированы с системами оркестровки, такими как Kubernetes, OpenShift, OpenStack и Mesos, и обеспечивают режимы изоляции для виртуальных машин, контейнеров/pod-ов и рабочих нагрузок без операционной системы. +* [Contrail](https://www.juniper.net/us/en/products-services/sdn/contrail/contrail-networking/), основан на [Tungsten Fabric](https://tungsten.io), представляет собой платформу для виртуализации мультиоблачных сетей с открытым исходным кодом и управления политиками. Contrail и Tungsten Fabric интегрированы с системами оркестрации, такими как Kubernetes, OpenShift, OpenStack и Mesos, и обеспечивают режимы изоляции для виртуальных машин, контейнеров/подов и рабочих нагрузок без операционной системы. * [Flannel](https://github.com/flannel-io/flannel#deploying-flannel-manually) - это поставщик оверлейной сети, который можно использовать с Kubernetes. -* [Knitter](https://github.com/ZTE/Knitter/) - это плагин для поддержки нескольких сетевых интерфейсов Kubernetes pod-ов. -* Multus - это плагин Multi для поддержки нексольких сетейв Kubernetes для поддержки всех CNI плагинов (наприме: Calico, Cilium, Contiv, Flannel), в дополнение к рабочим нагрузкам основанных на SRIOV, DPDK, OVS-DPDK и VPP в Kubernetes. -* [OVN-Kubernetes](https://github.com/ovn-org/ovn-kubernetes/) - это сетевой провайдер для Kubernetes основанный на [OVN (Open Virtual Network)](https://github.com/ovn-org/ovn/), реализация виртуалной сети a появившейся в результате проекта Open vSwitch (OVS). OVN-Kubernetes обеспечивает сетевую реализацию на основе наложения для Kubernetes, включая реализацию балансировки нагрузки и сетевой политики на основе OVS. -* [OVN4NFV-K8S-Plugin](https://github.com/opnfv/ovn4nfv-k8s-plugin) - это подключаемый модуль контроллера CNI на основе OVN для обеспечения облачной цепочки сервисных функций (SFC), несколько наложеных сетей OVN, динамического создания подсети, динамического создания виртуальных сетей, сети поставщика VLAN, сети прямого поставщика и подключаемого к другим Multi Сетевые плагины, идеально подходящие для облачных рабочих нагрузок на периферии в сети с несколькими кластерами. +* [Knitter](https://github.com/ZTE/Knitter/) - это плагин для поддержки нескольких сетевых интерфейсов Kubernetes подов. +* [Multus](https://github.com/k8snetworkplumbingwg/multus-cni) - это плагин Multi для работы с несколькими сетями в Kubernetes, который поддерживает большинство самых популярных [CNI](https://github.com/containernetworking/cni) (например: Calico, Cilium, Contiv, Flannel), в дополнение к рабочим нагрузкам основанных на SRIOV, DPDK, OVS-DPDK и VPP в Kubernetes. +* [OVN-Kubernetes](https://github.com/ovn-org/ovn-kubernetes/) - это сетевой провайдер для Kubernetes основанный на [OVN (Open Virtual Network)](https://github.com/ovn-org/ovn/), реализация виртуальной сети, появившийся в результате проекта Open vSwitch (OVS). OVN-Kubernetes обеспечивает сетевую реализацию на основе наложения для Kubernetes, включая реализацию балансировки нагрузки и сетевой политики на основе OVS. +* [OVN4NFV-K8S-Plugin](https://github.com/opnfv/ovn4nfv-k8s-plugin) - это подключаемый модуль контроллера CNI на основе OVN для обеспечения облачной цепочки сервисных функций (SFC), несколько наложенных сетей OVN, динамического создания подсети, динамического создания виртуальных сетей, сети поставщика VLAN, сети прямого поставщика и подключаемого к другим Multi Сетевые плагины, идеально подходящие для облачных рабочих нагрузок на периферии в сети с несколькими кластерами. * [NSX-T](https://docs.vmware.com/en/VMware-NSX-T/2.0/nsxt_20_ncp_kubernetes.pdf) плагин для контейнера (NCP) обеспечивающий интеграцию между VMware NSX-T и контейнерами оркестраторов, таких как Kubernetes, а так же интеграцию между NSX-T и контейнеров на основе платформы CaaS/PaaS, таких как Pivotal Container Service (PKS) и OpenShift. -* [Nuage](https://github.com/nuagenetworks/nuage-kubernetes/blob/v5.1.1-1/docs/kubernetes-1-installation.rst) - эта платформа SDN, которая обеспечивает сетевое взаимодействие на основе политик между Kubernetes Pod-ами и не Kubernetes окружением с отображением и мониторингом безопасности. -* [Romana](https://romana.io) - это сетевое решение уровня 3 для pod сетей, которое также поддерживает [NetworkPolicy API](/docs/concepts/services-networking/network-policies/). Подробности установки Kubeadm доступны [здесь](https://github.com/romana/romana/tree/master/containerize). -* [Weave Net](https://www.weave.works/docs/net/latest/kubernetes/kube-addon/) обеспечивает сетевуюи политику сетей, будет работать в сетевого раздела и не требует внешней базы данных. +* [Nuage](https://github.com/nuagenetworks/nuage-kubernetes/blob/v5.1.1-1/docs/kubernetes-1-installation.rst) - эта платформа SDN, которая обеспечивает сетевое взаимодействие на основе политик между Kubernetes подами и не Kubernetes окружением, с отображением и мониторингом безопасности. +* [Romana](https://romana.io) - это сетевое решение уровня 3 для сетей подов, которое также поддерживает [NetworkPolicy API](/docs/concepts/services-networking/network-policies/). Подробности установки Kubeadm доступны [здесь](https://github.com/romana/romana/tree/master/containerize). +* [Weave Net](https://www.weave.works/docs/net/latest/kubernetes/kube-addon/) предоставляет сеть и обеспечивает сетевую политику, будет работать на обеих сторонах сетевого раздела и не требует внешней базы данных. ## Обнаружение служб -* [CoreDNS](https://coredns.io) - это гибкий, расширяемый DNS-сервер, который может быть [установлен](https://github.com/coredns/deployment/tree/master/kubernetes) в качестве внутрикластерного DNS для pod-ов. +* [CoreDNS](https://coredns.io) - это гибкий, расширяемый DNS-сервер, который может быть [установлен](https://github.com/coredns/deployment/tree/master/kubernetes) в качестве внутрикластерного DNS для подов. ## Визуализация и контроль * [Dashboard](https://github.com/kubernetes/dashboard#kubernetes-dashboard) - это веб-интерфейс панели инструментов для Kubernetes. -* [Weave Scope](https://www.weave.works/documentation/scope-latest-installing/#k8s) - это инструмент для графической визуализации ваших контейнеров, pod-ов, сервисов и т.д. Используйте его вместе с [учетной записью Weave Cloud](https://cloud.weave.works/) или разместите пользовательский интерфейс самостоятельно. +* [Weave Scope](https://www.weave.works/documentation/scope-latest-installing/#k8s) - это инструмент для графической визуализации ваших контейнеров, подов, сервисов и т.д. Используйте его вместе с [учетной записью Weave Cloud](https://cloud.weave.works/) или разместите пользовательский интерфейс самостоятельно. ## Инфраструктура @@ -49,4 +49,4 @@ content_type: concept В устаревшем каталоге [cluster/addons](https://git.k8s.io/kubernetes/cluster/addons) задокументировано несколько других дополнений. -Ссылки на те, в хорошем состоянии, должны быть здесь. PR приветствуются! +Ссылки на те, в хорошем состоянии, должны быть здесь. Пул реквесты приветствуются! From 6525c0cab5d755aa3a1baf4bb172266bbd2c2f4b Mon Sep 17 00:00:00 2001 From: Ilya Z Date: Sat, 26 Mar 2022 23:55:11 +0400 Subject: [PATCH 051/102] kube_api_typos --- content/ru/docs/concepts/overview/kubernetes-api.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/content/ru/docs/concepts/overview/kubernetes-api.md b/content/ru/docs/concepts/overview/kubernetes-api.md index e2523c5191..e9a3debbc3 100644 --- a/content/ru/docs/concepts/overview/kubernetes-api.md +++ b/content/ru/docs/concepts/overview/kubernetes-api.md @@ -36,7 +36,7 @@ Kubernetes как таковой состоит из множества комп Все детали API документируется с использованием [OpenAPI](https://www.openapis.org/). Начиная с Kubernetes 1.10, API-сервер Kubernetes основывается на спецификации OpenAPI через конечную точку `/openapi/v2`. -Нужный формат устанавливается через HTTP-заголовоки: +Нужный формат устанавливается через HTTP-заголовки: Заголовок | Возможные значения ------ | --------------- @@ -61,11 +61,11 @@ GET /swagger-2.0.0.pb-v1.gz | GET /openapi/v2 **Accept**: application/com.github Чтобы упростить удаления полей или изменение ресурсов, Kubernetes поддерживает несколько версий API, каждая из которых доступна по собственному пути, например, `/api/v1` или `/apis/extensions/v1beta1`. -Мы выбрали версионирование API, а не конкретных ресурсов или полей, чтобы API отражал четкое и согласованное представление о системных ресурсах и их поведении, а также, чтобы разграничивать API, которые уже не поддерживаются и/или находятся в экспериментальной стадии. Схемы сериализации JSON и Protobuf следуют одним и тем же правилам по внесению изменений в схему, поэтому описание ниже охватывают оба эти формата. +Мы выбрали версионирование API, а не конкретных ресурсов или полей, чтобы API отражал четкое и согласованное представление о системных ресурсах и их поведении, а также, чтобы разграничивать API, которые уже не поддерживаются и/или находятся в экспериментальной стадии. Схемы сериализации JSON и Protobuf следуют одним и тем же правилам по внесению изменений в схему, поэтому описание ниже охватывают оба эти формата. -Обратите внимание, что версиоирование API и программное обеспечение косвенно связаны друг с другом. [Предложение по версионированию API и новых выпусков](https://git.k8s.io/community/contributors/design-proposals/release/versioning.md) описывает, как связаны между собой версии API с версиями программного обеспечения. +Обратите внимание, что версионирование API и программное обеспечение косвенно связаны друг с другом. [Предложение по версионированию API и новых выпусков](https://git.k8s.io/community/contributors/design-proposals/release/versioning.md) описывает, как связаны между собой версии API с версиями программного обеспечения. -Разные версии API имеют характеризуются разной уровнем стабильностью и поддержкой. Критерии каждого уровня более подробно описаны в [документации изменений API](https://git.k8s.io/community/contributors/devel/sig-architecture/api_changes.md#alpha-beta-and-stable-versions). Ниже приводится краткое изложение: +Разные версии API характеризуются разными уровнями стабильности и поддержки. Критерии каждого уровня более подробно описаны в [документации изменений API](https://git.k8s.io/community/contributors/devel/sig-architecture/api_changes.md#alpha-beta-and-stable-versions). Ниже приводится краткое изложение: - Альфа-версии: - Названия версий включают надпись `alpha` (например, `v1alpha1`). @@ -79,7 +79,7 @@ GET /swagger-2.0.0.pb-v1.gz | GET /openapi/v2 **Accept**: application/com.github - Поддержка функциональности в целом не будет прекращена, хотя кое-что может измениться. - Схема и/или семантика объектов может стать несовместимой с более поздними бета-версиями или стабильными выпусками. Когда это случится, мы даем инструкции по миграции на следующую версию. Это обновление может включать удаление, редактирование и повторного создание API-объектов. Этот процесс может потребовать тщательного анализа. Кроме этого, это может привести к простою приложений, которые используют данную функциональность. - Рекомендуется только для неосновного производственного использования из-за риска возникновения возможных несовместимых изменений с будущими версиями. Если у вас есть несколько кластеров, которые возможно обновить независимо, вы можете снять это ограничение. - - **Пожалуйста, попробуйте в действии бета-версии функциональности и поделитесь своими впечатлениями! После того, как функциональность выйдет из бета-версии, нам может быть нецелесообразно что-то дальше изменять.** + - **Пожалуйста, попробуйте в действии бета-версии функциональности и поделитесь своими впечатлениями! После того как функциональность выйдет из бета-версии, нам может быть нецелесообразно что-то дальше изменять.** - Стабильные версии: - Имя версии `vX`, где `vX` — целое число. - Стабильные версии функциональностей появятся в новых версиях. @@ -113,5 +113,3 @@ DaemonSets, Deployments, StatefulSet, NetworkPolicies, PodSecurityPolicies и Re Например: чтобы включить deployments и daemonsets, используйте флаг `--runtime-config=extensions/v1beta1/deployments=true,extensions/v1beta1/daemonsets=true`. {{< note >}}Включение/отключение отдельных ресурсов поддерживается только в API-группе `extensions/v1beta1` по историческим причинам.{{< /note >}} - - From 6319b586d6df260b46e013fc1a385af6a543f7be Mon Sep 17 00:00:00 2001 From: Ilya Z Date: Sun, 27 Mar 2022 01:03:40 +0400 Subject: [PATCH 052/102] content-guide_fix --- .../ru/docs/contribute/style/content-guide.md | 80 +++++++++---------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/content/ru/docs/contribute/style/content-guide.md b/content/ru/docs/contribute/style/content-guide.md index bfb0073357..58cbc6af7c 100644 --- a/content/ru/docs/contribute/style/content-guide.md +++ b/content/ru/docs/contribute/style/content-guide.md @@ -25,72 +25,72 @@ card: ### Контент, полученный из двух источников -Документация Kubernetes не содержит дублированный контент, полученный из разных мест (так называемый **контент из двумя источниками**). Контент из двух источников требует дублирования работы со стороны мейнтейнеров проекта и к тому же быстро теряет актуальность. +Документация Kubernetes не содержит дублированный контент, полученный из разных мест (так называемый **контент из двух источников**). Контент из двух источников требует дублирования работы со стороны мейнтейнеров проекта и к тому же быстро теряет актуальность. Перед добавлением контента, задайте себе вопрос: -- Новая информация относится к действующему проекту CNCF ИЛИ проекту в организациях на GitHub kubernetes или kubernetes-sigs? +- Новая информация относится к действующему проекту CNCF или проекту в организациях на GitHub kubernetes или kubernetes-sigs? - Если да, то: - У этого проекта есть собственная документация? - - если да, то укажите ссылку на документацию проекта в документации Kubernetes - - если нет, добавьте информацию в репозиторий проекта (если это возможно), а затем укажите ссылку на неё в документации Kubernetes + - если да, то укажите ссылку на документацию проекта в документации Kubernetes. + - если нет, добавьте информацию в репозиторий проекта (если это возможно), а затем укажите ссылку на неё в документации Kubernetes. - Если нет, то: - Остановитесь! - - Добавление информации по продуктам от других разработчиков не допускается + - Добавление информации о продуктах от других разработчиков не допускается. - Не разрешено ссылаться на документацию и сайты сторонних разработчиков. ### Разрешенная и запрещённая информация Есть несколько условий, когда в документации Kubernetes может быть информация, относящиеся не к проектам Kubernetes. -Ниже перечислены основные категории по содержанию проектов, не касающихся к Kubernetes, а также приведены рекомендации о том, что разрешено, а что нет: +Ниже перечислены основные категории по содержанию проектов, не касающихся Kubernetes, а также приведены рекомендации о том, что разрешено, а что нет: -1. Инструкции по установке или эксплуатации Kubernetes, которые не связаны с проектами Kubernetes +1. Инструкции по установке или эксплуатации Kubernetes, которые не связаны с проектами Kubernetes. - Разрешено: - - Ссылаться на документацию на CNCF-проекта или на проект в GitHub-организациях kubernetes или kubernetes-sigs - - Пример: для установки Kubernetes в процессе обучения нужно обязательно установить и настроить minikube, а также сослаться на соответствующую документацию minikube - - Добавление инструкций для проектов в организации kubernetes или kubernetes-sigs, если по ним нет инструкций - - Пример: добавление инструкций по установке и решению неполадок [kubadm](https://github.com/kubernetes/kubeadm) + - Ссылаться на документацию CNCF-проекта или на проект в GitHub-организациях kubernetes или kubernetes-sigs. + - Пример: для установки Kubernetes в процессе обучения нужно обязательно установить и настроить minikube, а также сослаться на соответствующую документацию minikube. + - Добавление инструкций для проектов в организации kubernetes или kubernetes-sigs, если по ним нет инструкций. + - Пример: добавление инструкций по установке и решению неполадок [kubeadm](https://github.com/kubernetes/kubeadm). - Запрещено: - - Добавление информацию, которая повторяет документацию в другом репозитории + - Добавление информации, которая дублирует документацию в другом репозитории. - Примеры: - - Добавление инструкций по установке и настройке minikube; Minikube имеет собственную [документацию](https://minikube.sigs.k8s.io/docs/), которая включают эти инструкции - - Добавление инструкций по установке Docker, CRI-O, containerd и других окружений для выполнения контейнеров в разных операционных системах + - Добавление инструкций по установке и настройке minikube; Minikube имеет собственную [документацию](https://minikube.sigs.k8s.io/docs/), которая включают эти инструкции. + - Добавление инструкций по установке Docker, CRI-O, containerd и других окружений для выполнения контейнеров в разных операционных системах. - Добавление инструкций по установке Kubernetes в промышленных окружениях, используя разные проекты: - -Kubernetes Rebar Integrated Bootstrap (KRIB) — это проект стороннего разработчика, поэтому все содержимое находится репозитории разработчика. + - Kubernetes Rebar Integrated Bootstrap (KRIB) — это проект стороннего разработчика, поэтому всё содержимое находится в репозитории разработчика. - У проекта [Kubernetes Operations (kops)](https://github.com/kubernetes/kops) есть инструкции по установке и руководства в GitHub-репозитории. - - У проекта [Kubespray](https://kubespray.io) есть собственная документация - - Добавление руководства, в котором объясняется, как выполнить задачу с использованием продукта определенного разработчика или проекта с открытым исходным кодом, не являющиеся CNCF-проектом или проектом в GitHub-организациях kubernetes или kubnetes-sigs. - - Добавление руководства по использованию CNCF-проекта или проекта в GitHub-организациях kubernetes или kubnetes-sigs, если у проекта есть собственная документация -1. Подробное описание технических аспектов по использованию стороннего проекта (не Kubernetes) или как этот проект разработан + - У проекта [Kubespray](https://kubespray.io) есть собственная документация. + - Добавление руководства, в котором объясняется, как выполнить задачу с использованием продукта определенного разработчика или проекта с открытым исходным кодом, не являющиеся CNCF-проектами или проектом в GitHub-организациях kubernetes, или kubernetes-sigs. + - Добавление руководства по использованию CNCF-проекта или проекта в GitHub-организациях kubernetes или kubernetes-sigs, если у проекта есть собственная документация. +1. Подробное описание технических аспектов по использованию стороннего проекта (не Kubernetes) или как этот проект разработан. Добавление такого типа информации в документацию Kubernetes не допускается. -1. Информация стороннему проекту +1. Информация стороннему проекту. - Разрешено: - - Добавление краткого введения о CNCF-проекте или проекте в GitHub-организациях kubernetes или kubernetes-sigs; этот абзац может содержать ссылки на проект + - Добавление краткого введения о CNCF-проекте или проекте в GitHub-организациях kubernetes или kubernetes-sigs; этот абзац может содержать ссылки на проект. - Запрещено: - - Добавление информации по продукту определённого разработчика - - Добавление информации по проекту с открытым исходным кодом, который не является CNCF-проектом или проектом в GitHub-организациях kubernetes или kubnetes-sigs - - Добавление информации, дублирующего документацию из другого проекта, независимо от оригинального репозитория - - Пример: добавление документации для проекта [Kubernetes in Docker (KinD)](https://kind.sigs.k8s.io) в документацию Kubernetes -1. Только ссылки на сторонний проект + - Добавление информации по продукту определённого разработчика. + - Добавление информации по проекту с открытым исходным кодом, который не является CNCF-проектом или проектом в GitHub-организациях kubernetes или kubernetes-sigs. + - Добавление информации, дублирующего документацию из другого проекта, независимо от оригинального репозитория. + - Пример: добавление документации для проекта [Kubernetes in Docker (KinD)](https://kind.sigs.k8s.io) в документацию Kubernetes. +1. Только ссылки на сторонний проект. - Разрешено: - - Ссылаться на проекты в GitHub-организациях kubernetes и kubernetes-sigs - - Пример: добавление ссылок на [документацию](https://kind.sigs.k8s.io/docs/user/quick-start) проекта Kubernetes in Docker (KinD), который находится в GitHub-организации kubernetes-sigs - - Добавление ссылок на действующие CNCF-проекты - - Пример: добавление ссылок на [документацию](https://prometheus.io/docs/introduction/overview/) проекта Prometheus; Prometheus — это действующий проект CNCF + - Ссылаться на проекты в GitHub-организациях kubernetes и kubernetes-sigs. + - Пример: добавление ссылок на [документацию](https://kind.sigs.k8s.io/docs/user/quick-start) проекта Kubernetes in Docker (KinD), который находится в GitHub-организации kubernetes-sigs. + - Добавление ссылок на действующие CNCF-проекты. + - Пример: добавление ссылок на [документацию](https://prometheus.io/docs/introduction/overview/) проекта Prometheus; Prometheus — это действующий проект CNCF. - Запрещено: - - Ссылаться на продукты стороннего разработчика - - Ссылаться на архивированные проекты CNCF - - Ссылаться на недействующие проекты в организациях GitHub в kubernetes и kubernetes-sigs - - Ссылаться на проекты с открытым исходным кодом, которые не являются проектами CNCF или не находятся в организациях GitHub kubernetes или kubernetes-sigs. -1. Содержание учебных курсов + - Ссылаться на продукты стороннего разработчика. + - Ссылаться на прекращенные проекты CNCF. + - Ссылаться на недействующие проекты в организациях GitHub в kubernetes и kubernetes-sigs. + - Ссылаться на проекты с открытым исходным кодом, которые не являются проектами CNCF или не находятся в организациях GitHub kubernetes, или kubernetes-sigs. +1. Содержание учебных курсов. - Разрешено: - - Ссылаться на независимые от разработчиков учебные курсы Kubernetes, предлагаемыми [CNCF](https://www.cncf.io/), [Linux Foundation](https://www.linuxfoundation.org/) и [Linux Academy](https://linuxacademy.com/) (партнер Linux Foundation) - - Пример: добавление ссылок на курсы Linux Academy, такие как [Kubernetes Quick Start](https://linuxacademy.com/course/kubernetes-quick-start/) в [Kubernetes Security](https://linuxacademy.com/course/kubernetes-security/) + - Ссылаться на независимые от разработчиков учебные курсы Kubernetes, предлагаемыми [CNCF](https://www.cncf.io/), [Linux Foundation](https://www.linuxfoundation.org/) и [Linux Academy](https://linuxacademy.com/) (партнер Linux Foundation). + - Пример: добавление ссылок на курсы Linux Academy, такие как [Kubernetes Quick Start](https://linuxacademy.com/course/kubernetes-quick-start/) и [Kubernetes Security](https://linuxacademy.com/course/kubernetes-security/). - Запрещено: - - Ссылаться на учебныЕе онлайн-курсы, вне CNCF, Linux Foundation или Linux Academy; документация Kubernetes не содержит ссылок на сторонний контент + - Ссылаться на учебные онлайн-курсы, не относящиеся к CNCF, Linux Foundation или Linux Academy; документация Kubernetes не содержит ссылок на сторонний контент. - Пример: добавление ссылок на учебные руководства или курсы Kubernetes на Medium, KodeKloud, Udacity, Coursera, learnk8s и т.д. - - Ссылаться на руководства определённых разработчиков вне зависимости от обучающей организации - - Пример: добавление ссылок на такие курсы Linux Academy, как [Google Kubernetes Engine Deep Dive](https://linuxacademy.com/google-cloud-platform/training/course/name/google-kubernetes-engine-deep-dive) and [Amazon EKS Deep Dive](https://linuxacademy.com/course/amazon-eks-deep-dive/) + - Ссылаться на руководства определённых разработчиков вне зависимости от обучающей организации. + - Пример: добавление ссылок на такие курсы Linux Academy, как [Google Kubernetes Engine Deep Dive](https://linuxacademy.com/google-cloud-platform/training/course/name/google-kubernetes-engine-deep-dive) и [Amazon EKS Deep Dive](https://linuxacademy.com/course/amazon-eks-deep-dive/) Если у вас есть вопросы по поводу допустимого контента, присоединяйтесь к каналу #sig-docs в [Slack Kubernetes](http://slack.k8s.io/)! From 9f0afaf0c344e1f81328ec22e43ffc0667219344 Mon Sep 17 00:00:00 2001 From: Ilya Z Date: Sun, 27 Mar 2022 01:41:03 +0400 Subject: [PATCH 053/102] advanced_guide_edited --- content/ru/docs/contribute/advanced.md | 76 +++++++++++++------------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/content/ru/docs/contribute/advanced.md b/content/ru/docs/contribute/advanced.md index dfe68fa685..bb4ff9a35f 100644 --- a/content/ru/docs/contribute/advanced.md +++ b/content/ru/docs/contribute/advanced.md @@ -1,5 +1,5 @@ --- -title: Участие для опытных +title: Существенный вклад slug: advanced content_type: concept weight: 30 @@ -22,20 +22,20 @@ weight: 30 - Ежедневно проверять [открытые пулреквесты](https://github.com/kubernetes/website/pulls) для контроля качества и соблюдения рекомендаций по [оформлению](/docs/contribute/style/style-guide/) и [содержимому](/docs/contribute/style/content-guide/). - В первую очередь просматривайте самые маленькие пулреквесты (`size/XS`), и только потом беритесь за самые большие (`size/XXL`). - Проверяйте столько пулреквестов, сколько сможете. -- Проследить, что CLA подписан каждым участником. +- Проследите, что CLA подписан каждым участником. - Помогайте новым участникам подписать [CLA](https://github.com/kubernetes/community/blob/master/CLA.md). - - Используйте [этот](https://github.com/zparnold/k8s-docs-pr-botherer) скрипт, чтобы автоматически напомнить участникам, не подписавшим CLA, чтобы они подписали CLA. + - Используйте [этот](https://github.com/zparnold/k8s-docs-pr-botherer) скрипт, чтобы автоматически напомнить участникам, не подписавшим CLA, подписать его. - Оставить свое мнение о предложенных изменениях и поспособствовать в проведении технического обзора от членов других SIG-групп. - Предложить исправления для измененного контента в PR. - Если вы хотите убедиться в правильности контента, прокомментируйте PR и задайте уточняющие вопросы. - - Добавьте нужны метки с `sig/`. - - Если нужно, то назначьте рецензентов из секции `reviewers:` в фронтальной части файла. + - Добавьте нужные метки с `sig/`. + - Если нужно, то назначьте рецензентов из секции `reviewers:` в верхней части файла. - Добавьте метки `Docs Review` и `Tech Review` для установки статуса проверки PR. - Добавьте метку `Needs Doc Review` или `Needs Tech Review` для пулреквестов, которые ещё не были проверены. - Добавьте метку `Doc Review: Open Issues` или `Tech Review: Open Issues` для пулреквестов, которые были проверены и требуют дополнительную информацию и выполнение действия перед слиянием. - Добавьте метки `/lgtm` и `/approve` для пулреквестов, которые могут быть приняты. - Объедините пулреквесты, если они готовы, либо закройте те, которые не могут быть приняты. -- Ежедневно отсортируйте и пометьте новые заявки. Обратитесь к странице [Участие для опытных](/ru/docs/contribute/intermediate/) для получения информации по использование метаданных SIG Docs. +- Ежедневно отсортируйте и пометьте новые заявки. Обратитесь к странице [Участие для опытных](/ru/docs/contribute/intermediate/) для получения информации по использованию метаданных SIG Docs. ### Полезные ссылки на GitHub для дежурных @@ -43,9 +43,9 @@ weight: 30 - [Нет CLA, нет права на слияние](https://github.com/kubernetes/website/pulls?q=is%3Aopen+is%3Apr+label%3A%22cncf-cla%3A+no%22+-label%3Ado-not-merge+label%3Alanguage%2Fen): напомните участнику подписать CLA. Если об этом уже напомнил и бот, и человек, то закройте PR и напишите автору, что он может открыть свой PR после подписания CLA. **Не проверяйте PR, если их авторы не подписали CLA!** -- [Требуется LGTM](https://github.com/kubernetes/website/pulls?utf8=%E2%9C%93&q=is%3Aopen+is%3Apr+-label%3Ado-not-merge+label%3Alanguage%2Fen+-label%3Algtm+): если нужен проверка с технической точки зрения, попросите её провести одного из рецензентов, который предложил бот. Если требуется просмотр пулреквест со стороны группы документации или вычитка, то предложите изменения, либо сами измените PR, чтобы ускорить процесс принятия пулреквеста. -- [Имеет LGTM, нужно одобрение со стороны группы документации](https://github.com/kubernetes/website/pulls?q=is%3Aopen+is%3Apr+-label%3Ado-not-merge+label%3Alanguage%2Fen+label%3Algtm): выясните, нужно ли внести какие-либо дополнительные изменения или обновления, чтобы принять PR. Если по вашему мнению PR готов к слияния, оставьте комментарий с текстом `/approve`. -- [Быстрые результаты](https://github.com/kubernetes/website/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+base%3Amaster+-label%3A%22do-not-merge%2Fwork-in-progress%22+-label%3A%22do-not-merge%2Fhold%22+label%3A%22cncf-cla%3A+yes%22+label%3A%22size%2FXS%22+label%3A%22language%2Fen%22+): если маленький PR направлен в основную ветку и не имеет условий для объединения. (поменяйте "XS" в метке с размером при работе с другими пулреквестами [XS, S, M, L, XL, XXL]). +- [Требуется LGTM](https://github.com/kubernetes/website/pulls?utf8=%E2%9C%93&q=is%3Aopen+is%3Apr+-label%3Ado-not-merge+label%3Alanguage%2Fen+-label%3Algtm+): если нужна проверка с технической точки зрения, попросите её провести одного из рецензентов, которого предложил бот. Если требуется просмотр пулреквеста со стороны группы документации или вычитка, то предложите изменения, либо сами измените PR, чтобы ускорить процесс принятия пулреквеста. +- [Имеет LGTM, нужно одобрение со стороны группы документации](https://github.com/kubernetes/website/pulls?q=is%3Aopen+is%3Apr+-label%3Ado-not-merge+label%3Alanguage%2Fen+label%3Algtm): выясните, нужно ли внести какие-либо дополнительные изменения или обновления, чтобы принять PR. Если по вашему мнению PR готов к слиянию, оставьте комментарий с текстом `/approve`. +- [Быстрые результаты](https://github.com/kubernetes/website/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+base%3Amaster+-label%3A%22do-not-merge%2Fwork-in-progress%22+-label%3A%22do-not-merge%2Fhold%22+label%3A%22cncf-cla%3A+yes%22+label%3A%22size%2FXS%22+label%3A%22language%2Fen%22+): если маленький PR направлен в основную ветку и не имеет условий для объединения (поменяйте "XS" в метке с размером при работе с другими пулреквестами [XS, S, M, L, XL, XXL]). - [Вне основной ветки](https://github.com/kubernetes/website/pulls?utf8=%E2%9C%93&q=is%3Aopen+is%3Apr+-label%3Ado-not-merge+label%3Alanguage%2Fen+-base%3Amaster): если PR отправлен в ветку `dev-`, значит он предназначается для будущего выпуска. Убедитесь, что [release meister](https://github.com/kubernetes/sig-release/tree/master/release-team) знает об этом, добавив комментарий с `/assign @`. Если он направлен в старую ветку, помогите автору PR изменить на более подходящую ветку. ### Когда закрывать пулреквесты @@ -57,7 +57,7 @@ weight: 30 - Закройте любой PR, если автор не отреагировал на комментарии или проверки в течение 2 или более недель. -Не бойтесь закрывать пулреквесты. Участники с лёгкостью открыть и возобновить незаконченную работу. Зачастую уведомление о закрытии стимулировать автора возобновить и закончить свой вклад. +Не бойтесь закрывать пулреквесты. Участники с лёгкостью могут открыть и возобновить незаконченную работу. Зачастую уведомление о закрытии стимулирует автора возобновить и завершить свою работу до конца. Чтобы закрыть пулреквест, оставьте комментарий `/close` в PR. @@ -71,8 +71,8 @@ weight: 30 [Члены](/ru/docs/contribute/participating/#члены) SIG Docs могут предлагать улучшения. -После того, как вы давно начали работать над документацией Kubernetes, у наверняка появились какие-нибудь идеи по улучшению [руководства по оформлению](/docs/contribute/style/style-guide/), [руководства по оформлению](/docs/contribute/style/content-guide/), набору инструментов, который используется для создания документации, стилизации сайта, процессов проверки и объединения пулреквестов. Для максимальной открытости подобные типы предложений по улучшению должны обсуждаться на встречи SIG Docs или в [списке рассылки kubernetes-sig-docs](https://groups.google.com/forum/#!forum/kubernetes-sig-docs). -Помимо этого, это поможет разъяснить, как всё устроено в данный момент, и объяснить, почему так было принято, прежде чем предлагать радикальные изменения. Самый быстрый способ узнать ответы на вопросы о том, как в настоящее время работает документация, это задать их на канале `#sig-docs` Slack на [kubernetes.slack.com](https://kubernetes.slack.com). +Если вы давно начали работать над документацией Kubernetes, у вас наверняка появились какие-нибудь идеи по улучшению [руководства по оформлению](/docs/contribute/style/style-guide/), [руководства по содержанию](/docs/contribute/style/content-guide/), набору инструментов, который используется для создания документации, стилизации сайта, процессов проверки и объединения пулреквестов. Для максимальной открытости подобные типы предложений по улучшению должны обсуждаться на встречи SIG Docs или в [списке рассылки kubernetes-sig-docs](https://groups.google.com/forum/#!forum/kubernetes-sig-docs). +Помимо этого, это поможет разъяснить, как всё устроено в данный момент, и объяснить, почему так было принято, прежде чем предлагать радикальные изменения. Самый быстрый способ узнать ответы на вопросы о том, как в настоящее время работает документация, это задать их в канале `#sig-docs` в [официальном Slack](https://kubernetes.slack.com). Когда обсуждение состоялось, а SIG-группа согласилась с желаемым результатом, вы можете работать над предлагаемыми изменениями наиболее приемлемым способом. Например, обновление руководства по оформлению или функциональности сайта может включать открытие пулреквеста, а изменение, связанное с тестированием документации, может предполагать взаимодействие с sig-testing. @@ -84,11 +84,11 @@ weight: 30 Представитель SIG Docs для данного выпуска координирует следующие задачи: -- Мониторинг электронной таблицы с отслеживанием функциональности на наличие новых или измененных возможностей, затрагивают документацию. Если документация для определенной функциональности не будет готова к выпуску, возможно, она не попадет в выпуск. -- Регулярное посещение встречи sig-release и обновлять информацию о статусе документации в выпуске. +- Мониторинг электронной таблицы с отслеживанием функциональности на наличие новых или измененных возможностей, затрагивающих документацию. Если документация для определенной функциональности не будет готова к выпуску, возможно, она не попадет в выпуск. +- Регулярное посещение встречи sig-release и обновление информации о статусе документации к выпуску. - Проверка и вычитка документации по функциональности, подготовленной SIG-группой, ответственной за реализацию этой функциональности. - Объединение связанных с выпуском пулреквестов и поддержка Git-ветки выпуска. -- Консультируйте других участников SIG Docs, которые хотят научиться выполнять эту роль в будущем. Это называется сопровождение (shadowing). +- Консультирование других участников SIG Docs, которые хотят научиться выполнять эту роль в будущем. Это называется сопровождение (shadowing). - Публикация изменений в документации, связанные с выпуском при размещении артефактов. Координация выпуска обычно занимает 3-4 месяца, а обязанности распределяются между утверждающими SIG Docs. @@ -101,10 +101,10 @@ weight: 30 Обязанности амбассадоров новых участников включают в себя: -- Отвечать на вопросы новых участников на [Slack-канале Kubernetes #sig-docs](https://kubernetes.slack.com). +- Отвечать на вопросы новых участников в [Slack-канале Kubernetes #sig-docs](https://kubernetes.slack.com). - Совместно работать с дежурным по PR, чтобы определять заявки, которые подойдут для решения новыми участниками. - Консультировать новых участников в их PR. -- Помогать новых участникам в создании более сложных PR, чтобы они могли стать членами Kubernetes. +- Помогать новым участникам в создании более сложных PR, чтобы они могли стать членами Kubernetes. - [Оказывать содействие участникам](/ru/docs/contribute/advanced/#поддержка-нового-участника) на их пути становления членом в Kubernetes. Текущие амбассадоры новых участников объявляются на каждом собрании SIG Docs и на канале [#sig-docs в Kubernetes](https://kubernetes.slack.com). @@ -115,7 +115,7 @@ weight: 30 Если участник сделал 5 значительных пулреквестов в один или несколько репозиториев Kubernetes, он имеет право на [членство](/ru/docs/contribute/participating#члены) в организации Kubernetes. Членство участника должно быть поддержано двумя спонсорами, которые уже являются рецензентами. -Новые участники документации могут найти спонсоров в канале #sig-docs в [в Slack Kubernetes](https://kubernetes.slack.com) или в [списке рассылки SIG Docs](https://groups.google.com/forum/#!forum/kubernetes-sig-docs). Если вы осознали полезность работы автора заявки на членство, вы добровольно можете поддержать (спонсировать) его. Когда они подадут заявку на членство, отреагируйте на заявку "+1" и напишите подробный комментарий о том, почему вы считаете, что кандидат отлично вписывается в члены организации Kubernetes. +Новые участники документации могут найти спонсоров в канале #sig-docs [в Slack Kubernetes](https://kubernetes.slack.com) или в [списке рассылки SIG Docs](https://groups.google.com/forum/#!forum/kubernetes-sig-docs). Если вы осознали полезность работы автора заявки на членство, вы добровольно можете поддержать (спонсировать) его. Когда они подадут заявку на членство, отреагируйте на заявку "+1" и напишите подробный комментарий о том, почему вы считаете, что кандидат отлично вписывается в члены организации Kubernetes. ## Сопредседатель SIG @@ -125,9 +125,9 @@ weight: 30 Сопредседатели должны соответствовать следующим требованиям: -- Быть утверждающим SIG Docs не меньше 6 месяцев -- [Руководить выпуском документации Kubernetes](/docs/contribute/advanced/#coordinate-docs-for-a-kubernetes-release) или сопровождать два выпуска -- Понимание рабочих процессов и инструментов SIG Docs: git, Hugo, локализация, блог +- Быть утверждающими SIG Docs не меньше 6 месяцев. +- [Руководить выпуском документации Kubernetes](/docs/contribute/advanced/#coordinate-docs-for-a-kubernetes-release) или сопроводить два выпуска. +- Понимать рабочие процессы и инструменты SIG Docs: git, Hugo, локализация, блог. - Понимать, как другие SIG-группы и репозитории Kubernetes влияют на рабочий процесс SIG Docs, включая: [команды в k/org](https://github.com/kubernetes/org/blob/master/config/kubernetes/sig-docs/teams.yaml), [процессы в k/community](https://github.com/kubernetes/community/tree/master/sig-docs), плагины в [k/test-infra](https://github.com/kubernetes/test-infra/) и роль [SIG Architecture](https://github.com/kubernetes/community/tree/master/sig-architecture). - Уделять не менее 5 часов в неделю (но зачастую больше) в течение как минимум 6 месяцев для выполнения обязанностей. @@ -137,13 +137,13 @@ weight: 30 Обязанности включают в себя: -- Сосредоточить группу SIG Docs на достижении максимального счастья для разработчиков через отличную документацию -- Быть примером соблюдения [норм поведения сообщества]https://github.com/cncf/foundation/blob/master/code-of-conduct.md) и контролировать их выполнение членами SIG -- Изучение и внедрение передовых практик для SIG-группы, обновляя рекомендации по участию -- Планирование и проведение встреч SIG: еженедельные обновления информации, ежеквартальные ретроспективные/плановые совещания и многое другое -- Планирование и проведение спринтов по документации на мероприятиях KubeCon и других конференциях +- Сосредоточить группу SIG Docs на достижении максимального счастья для разработчиков через отличную документацию. +- Быть примером соблюдения [норм поведения сообщества](https://github.com/cncf/foundation/blob/master/code-of-conduct.md) и контролировать их выполнение членами SIG. +- Изучать и внедрять передовые практики для SIG-группы, обновляя рекомендации по участию. +- Планировать и проверять встречи SIG: еженедельные обновления информации, ежеквартальные ретроспективные/плановые совещания и многое другое. +- Планирование и проведение спринтов по документации на мероприятиях KubeCon и других конференциях. - Набирать персонал и выступать в поддержку {{< glossary_tooltip text="CNCF" term_id="cncf" >}} и его платиновых партнеров, включая Google, Oracle, Azure, IBM и Huawei. -- Поддерживать нормальную работу SIG +- Поддерживать нормальную работу SIG. ### Проведение продуктивных встреч @@ -155,33 +155,33 @@ weight: 30 **Сформулируйте четкую повестку дня**: -- Определите конкретную цель встречи -- Опубликуйте программу дня заранее +- Определите конкретную цель встречи. +- Опубликуйте программу дня заранее. Для еженедельных встреч скопируйте примечания из предыдущей недели в раздел "Past meetings". **Работайте вместе для создания точных примечания**: -- Запишите обсуждение встречи -- Подумайте над тем, чтобы делегировать роль стенографист кому-нибудь другому +- Запишите обсуждение встречи. +- Подумайте над тем, чтобы делегировать роль стенографиста кому-нибудь другому. **Определяйте решения по пунктам повестки четко и точно**: -- Записывайте решения по пунктам, кто будет ими заниматься и ожидаемую дату завершения +- Записывайте решения по пунктам, кто будет ими заниматься и ожидаемую дату завершения. **Руководите обсуждением, когда это необходимо**: -- Если обсуждение выходит за пределы повестки дня, снова обратите внимание участников на обсуждаемую тему -- Найдите место для различных стилей ведения обсуждения, не отвлекаясь от темы обсуждения и уважая время людей +- Если обсуждение выходит за пределы повестки дня, снова обратите внимание участников на обсуждаемую тему. +- Найдите место для различных стилей ведения обсуждения, не отвлекаясь от темы обсуждения и уважая время людей. **Уважайте время людей**: -- Начинайте и заканчивайте встречи своевременно +- Начинайте и заканчивайте встречи своевременно. **Используйте Zoom эффективно**: -- Ознакомьтесь с [рекомендациями Zoom для Kubernetes](https://github.com/kubernetes/community/blob/master/communication/zoom-guidelines.md) -- Попробуйте попроситься быть ведущим в самом начале встречи, введя ключ ведущего +- Ознакомьтесь с [рекомендациями Zoom для Kubernetes](https://github.com/kubernetes/community/blob/master/communication/zoom-guidelines.md). +- Попробуйте попроситься быть ведущим в самом начале встречи, введя ключ ведущего. Исполнение роли ведущего в Zoom @@ -192,5 +192,3 @@ weight: 30 Если нужно остановить запись, нажмите на кнопку Stop. Запись автоматически загрузится на YouTube. - - From 5bb9befe1cc6825417feee42e441cf506f29e427 Mon Sep 17 00:00:00 2001 From: Edith Puclla <58795858+edithturn@users.noreply.github.com> Date: Sat, 26 Mar 2022 17:37:45 -0500 Subject: [PATCH 054/102] Update content/es/docs/concepts/storage/storage-limits.md Co-authored-by: Victor Morales --- content/es/docs/concepts/storage/storage-limits.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/es/docs/concepts/storage/storage-limits.md b/content/es/docs/concepts/storage/storage-limits.md index 5bcbfc6b20..552d38d0f0 100644 --- a/content/es/docs/concepts/storage/storage-limits.md +++ b/content/es/docs/concepts/storage/storage-limits.md @@ -11,7 +11,7 @@ content_type: concept Esta página describe la cantidad máxima de Volúmenes que se pueden adjuntar a un Nodo para varios proveedores de nube. -Los proveedores de la nube como Google, Amazon y Microsoft suelen tener un límite en la cantidad de Volúmenes que se pueden adjuntar a un Nodo. Es importante que Kubernetes respete esos límites. De lo contrario, los pods planificados en un Nodo podrían quedarse atascados esperando que se conecten los Volúmenes. +Los proveedores de la nube como Google, Amazon y Microsoft suelen tener un límite en la cantidad de Volúmenes que se pueden adjuntar a un Nodo. Es importante que Kubernetes respete esos límites. De lo contrario, los Pods planificados en un Nodo podrían quedarse atascados esperando que los Volúmenes se conecten. From ecaffa667b1742c464a66aad48d09c7b6804cb16 Mon Sep 17 00:00:00 2001 From: Edith Puclla <58795858+edithturn@users.noreply.github.com> Date: Sat, 26 Mar 2022 17:38:28 -0500 Subject: [PATCH 055/102] Update content/es/docs/concepts/storage/storage-limits.md Co-authored-by: Victor Morales --- content/es/docs/concepts/storage/storage-limits.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/es/docs/concepts/storage/storage-limits.md b/content/es/docs/concepts/storage/storage-limits.md index 552d38d0f0..ce1b0f0f18 100644 --- a/content/es/docs/concepts/storage/storage-limits.md +++ b/content/es/docs/concepts/storage/storage-limits.md @@ -47,7 +47,7 @@ Los límites de Volumen dinámico son compatibles con los siguientes tipos de Vo - Azure Disk - CSI -Para los Volúmenes administrados por complementos de Volumen en árbol, Kubernetes determina automáticamente el tipo de Nodo y aplica la cantidad máxima adecuada de Volúmenes para el Nodo. Por ejemplo: +Para los Volúmenes administrados por in-tree plugins de Volumen, Kubernetes determina automáticamente el tipo de Nodo y aplica la cantidad máxima adecuada de Volúmenes para el Nodo. Por ejemplo: * En Google Compute Engine, From 6c24e33f922826d85a593a49a5e88cc47d051939 Mon Sep 17 00:00:00 2001 From: Edith Puclla <58795858+edithturn@users.noreply.github.com> Date: Sat, 26 Mar 2022 17:38:43 -0500 Subject: [PATCH 056/102] Update content/es/docs/concepts/storage/storage-limits.md Co-authored-by: Victor Morales --- content/es/docs/concepts/storage/storage-limits.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/es/docs/concepts/storage/storage-limits.md b/content/es/docs/concepts/storage/storage-limits.md index ce1b0f0f18..418b145c56 100644 --- a/content/es/docs/concepts/storage/storage-limits.md +++ b/content/es/docs/concepts/storage/storage-limits.md @@ -53,7 +53,7 @@ Para los Volúmenes administrados por in-tree plugins de Volumen, Kubernetes det Google Compute Engine, se pueden adjuntar hasta 127 Volúmenes a un Nodo, [según el tipo de Nodo](https://cloud.google.com/compute/docs/disks/#pdnumberlimits). -* Para los discos de Amazon EBS en los tipos de instancias M5,C5,R5,T3 y Z1D, Kubernetes permite que solo se adjunten 25 Volúmenes a un Nodo. Para otros tipos de instancias en +* Para los discos de Amazon EBS en los tipos de instancias M5,C5,R5,T3 y Z1D, Kubernetes permite que solo se adjunten 25 Volúmenes a un Nodo. Para otros tipos de instancias en Amazon Elastic Compute Cloud (EC2), Kubernetes permite adjuntar 39 Volúmenes a un Nodo. From b12f7e1ad3a924be537d63c3e1b37e79e5352172 Mon Sep 17 00:00:00 2001 From: Edith Puclla <58795858+edithturn@users.noreply.github.com> Date: Sat, 26 Mar 2022 17:39:03 -0500 Subject: [PATCH 057/102] Update content/es/docs/concepts/storage/storage-limits.md Co-authored-by: Victor Morales --- content/es/docs/concepts/storage/storage-limits.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/es/docs/concepts/storage/storage-limits.md b/content/es/docs/concepts/storage/storage-limits.md index 418b145c56..28cc16937f 100644 --- a/content/es/docs/concepts/storage/storage-limits.md +++ b/content/es/docs/concepts/storage/storage-limits.md @@ -60,7 +60,7 @@ Kubernetes permite adjuntar 39 Volúmenes a un Nodo. * En Azure, se pueden conectar hasta 64 discos a un Nodo, según el tipo de Nodo. Para obtener más detalles, consulte [Sizes for virtual machines in Azure](https://docs.microsoft.com/en-us/azure/virtual-machines/windows/sizes). * Si un controlador de almacenamiento CSI anuncia una cantidad máxima de Volúmenes para un Nodo (usando `NodeGetInfo`), el {{< glossary_tooltip text="kube-scheduler" term_id="kube-scheduler" >}} respeta ese límite. -Consulte las especificaciones de [CSI specifications](https://github.com/container-storage-interface/spec/blob/master/spec.md#nodegetinfo) para obtener más información. +Consulte las [especificaciones de CSI](https://github.com/container-storage-interface/spec/blob/master/spec.md#nodegetinfo) para obtener más información. * Para los Volúmenes administrados por complementos en árbol que se han migrado a un controlador CSI, la cantidad máxima de Volúmenes será la que informe el controlador CSI. From 01a210abdf283add0983c2069fd8491fad758a7e Mon Sep 17 00:00:00 2001 From: Edith Puclla <58795858+edithturn@users.noreply.github.com> Date: Sat, 26 Mar 2022 17:41:19 -0500 Subject: [PATCH 058/102] Update content/es/docs/concepts/storage/storage-limits.md Co-authored-by: Victor Morales --- content/es/docs/concepts/storage/storage-limits.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/content/es/docs/concepts/storage/storage-limits.md b/content/es/docs/concepts/storage/storage-limits.md index 28cc16937f..0cb4a376e8 100644 --- a/content/es/docs/concepts/storage/storage-limits.md +++ b/content/es/docs/concepts/storage/storage-limits.md @@ -1,8 +1,4 @@ --- -reviewers: -- edithturn -- raelga -- electrocucaracha title: Límites de Volumen específicos del Nodo content_type: concept --- From 280104545a42e6d222ba699db84615c4c44631f3 Mon Sep 17 00:00:00 2001 From: Edith Puclla <58795858+edithturn@users.noreply.github.com> Date: Sat, 26 Mar 2022 17:41:43 -0500 Subject: [PATCH 059/102] Update content/es/docs/concepts/storage/storage-limits.md Co-authored-by: Victor Morales --- content/es/docs/concepts/storage/storage-limits.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/es/docs/concepts/storage/storage-limits.md b/content/es/docs/concepts/storage/storage-limits.md index 0cb4a376e8..4a62a27c94 100644 --- a/content/es/docs/concepts/storage/storage-limits.md +++ b/content/es/docs/concepts/storage/storage-limits.md @@ -58,6 +58,6 @@ Kubernetes permite adjuntar 39 Volúmenes a un Nodo. * Si un controlador de almacenamiento CSI anuncia una cantidad máxima de Volúmenes para un Nodo (usando `NodeGetInfo`), el {{< glossary_tooltip text="kube-scheduler" term_id="kube-scheduler" >}} respeta ese límite. Consulte las [especificaciones de CSI](https://github.com/container-storage-interface/spec/blob/master/spec.md#nodegetinfo) para obtener más información. -* Para los Volúmenes administrados por complementos en árbol que se han migrado a un controlador CSI, la cantidad máxima de Volúmenes será la que informe el controlador CSI. +* Para los Volúmenes administrados por in-tree plugins que han sido migrados a un controlador CSI, la cantidad máxima de Volúmenes será la que informe el controlador CSI. From bf59d01af7fa73541a57af30cabc205f33c9bcb3 Mon Sep 17 00:00:00 2001 From: Mitesh Jain <47820816+miteshskj@users.noreply.github.com> Date: Sun, 27 Mar 2022 12:26:44 +0530 Subject: [PATCH 060/102] Fix broken link for attach labels in assign-pod-node.md --- content/en/docs/concepts/scheduling-eviction/assign-pod-node.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/concepts/scheduling-eviction/assign-pod-node.md b/content/en/docs/concepts/scheduling-eviction/assign-pod-node.md index c24e8a8c94..2e38eb6938 100644 --- a/content/en/docs/concepts/scheduling-eviction/assign-pod-node.md +++ b/content/en/docs/concepts/scheduling-eviction/assign-pod-node.md @@ -33,7 +33,7 @@ specific Pods: ## Node labels {#built-in-node-labels} Like many other Kubernetes objects, nodes have -[labels](/docs/concepts/overview/working-with-objects/labels/). You can [attach labels manually](/docs/tasks/confiure-pod-container/assign-pods-nodes/#add-a-label-to-a-node). +[labels](/docs/concepts/overview/working-with-objects/labels/). You can [attach labels manually](/docs/tasks/configure-pod-container/assign-pods-nodes/#add-a-label-to-a-node). Kubernetes also populates a standard set of labels on all nodes in a cluster. See [Well-Known Labels, Annotations and Taints](/docs/reference/labels-annotations-taints/) for a list of common node labels. From ed2ded76e3aafa3d383e71615024c0f528b79c0e Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Sun, 27 Mar 2022 15:19:12 +0800 Subject: [PATCH 061/102] [zh] modify busybox to busybox:1.28 in dir examples Signed-off-by: xin.li --- .../logging/two-files-counter-pod-agent-sidecar.yaml | 2 +- .../logging/two-files-counter-pod-streaming-sidecar.yaml | 6 +++--- .../zh/examples/admin/logging/two-files-counter-pod.yaml | 2 +- content/zh/examples/admin/resource/limit-range-pod-1.yaml | 8 ++++---- content/zh/examples/admin/resource/limit-range-pod-2.yaml | 8 ++++---- content/zh/examples/admin/resource/limit-range-pod-3.yaml | 2 +- content/zh/examples/application/job/cronjob.yaml | 2 +- content/zh/examples/application/job/job-tmpl.yaml | 2 +- content/zh/examples/debug/counter-pod.yaml | 2 +- content/zh/examples/pods/init-containers.yaml | 2 +- content/zh/examples/pods/inject/dependent-envars.yaml | 2 +- content/zh/examples/pods/security/hello-apparmor.yaml | 2 +- content/zh/examples/pods/security/security-context.yaml | 2 +- content/zh/examples/pods/share-process-namespace.yaml | 2 +- .../storage/projected-secret-downwardapi-configmap.yaml | 2 +- .../projected-secrets-nondefault-permission-mode.yaml | 2 +- .../pods/storage/projected-service-account-token.yaml | 2 +- content/zh/examples/pods/storage/projected.yaml | 2 +- .../zh/examples/service/networking/hostaliases-pod.yaml | 2 +- 19 files changed, 27 insertions(+), 27 deletions(-) diff --git a/content/zh/examples/admin/logging/two-files-counter-pod-agent-sidecar.yaml b/content/zh/examples/admin/logging/two-files-counter-pod-agent-sidecar.yaml index b37b616e6f..ddfb8104cb 100644 --- a/content/zh/examples/admin/logging/two-files-counter-pod-agent-sidecar.yaml +++ b/content/zh/examples/admin/logging/two-files-counter-pod-agent-sidecar.yaml @@ -5,7 +5,7 @@ metadata: spec: containers: - name: count - image: busybox + image: busybox:1.28 args: - /bin/sh - -c diff --git a/content/zh/examples/admin/logging/two-files-counter-pod-streaming-sidecar.yaml b/content/zh/examples/admin/logging/two-files-counter-pod-streaming-sidecar.yaml index 87bd198cfd..6b7d1f1201 100644 --- a/content/zh/examples/admin/logging/two-files-counter-pod-streaming-sidecar.yaml +++ b/content/zh/examples/admin/logging/two-files-counter-pod-streaming-sidecar.yaml @@ -5,7 +5,7 @@ metadata: spec: containers: - name: count - image: busybox + image: busybox:1.28 args: - /bin/sh - -c @@ -22,13 +22,13 @@ spec: - name: varlog mountPath: /var/log - name: count-log-1 - image: busybox + image: busybox:1.28 args: [/bin/sh, -c, 'tail -n+1 -f /var/log/1.log'] volumeMounts: - name: varlog mountPath: /var/log - name: count-log-2 - image: busybox + image: busybox:1.28 args: [/bin/sh, -c, 'tail -n+1 -f /var/log/2.log'] volumeMounts: - name: varlog diff --git a/content/zh/examples/admin/logging/two-files-counter-pod.yaml b/content/zh/examples/admin/logging/two-files-counter-pod.yaml index 6ebeb717a1..31bbed3cf8 100644 --- a/content/zh/examples/admin/logging/two-files-counter-pod.yaml +++ b/content/zh/examples/admin/logging/two-files-counter-pod.yaml @@ -5,7 +5,7 @@ metadata: spec: containers: - name: count - image: busybox + image: busybox:1.28 args: - /bin/sh - -c diff --git a/content/zh/examples/admin/resource/limit-range-pod-1.yaml b/content/zh/examples/admin/resource/limit-range-pod-1.yaml index 0457792af9..b9bd20d06a 100644 --- a/content/zh/examples/admin/resource/limit-range-pod-1.yaml +++ b/content/zh/examples/admin/resource/limit-range-pod-1.yaml @@ -5,7 +5,7 @@ metadata: spec: containers: - name: busybox-cnt01 - image: busybox + image: busybox:1.28 command: ["/bin/sh"] args: ["-c", "while true; do echo hello from cnt01; sleep 10;done"] resources: @@ -16,7 +16,7 @@ spec: memory: "200Mi" cpu: "500m" - name: busybox-cnt02 - image: busybox + image: busybox:1.28 command: ["/bin/sh"] args: ["-c", "while true; do echo hello from cnt02; sleep 10;done"] resources: @@ -24,7 +24,7 @@ spec: memory: "100Mi" cpu: "100m" - name: busybox-cnt03 - image: busybox + image: busybox:1.28 command: ["/bin/sh"] args: ["-c", "while true; do echo hello from cnt03; sleep 10;done"] resources: @@ -32,6 +32,6 @@ spec: memory: "200Mi" cpu: "500m" - name: busybox-cnt04 - image: busybox + image: busybox:1.28 command: ["/bin/sh"] args: ["-c", "while true; do echo hello from cnt04; sleep 10;done"] diff --git a/content/zh/examples/admin/resource/limit-range-pod-2.yaml b/content/zh/examples/admin/resource/limit-range-pod-2.yaml index efac440269..40da19c1ae 100644 --- a/content/zh/examples/admin/resource/limit-range-pod-2.yaml +++ b/content/zh/examples/admin/resource/limit-range-pod-2.yaml @@ -5,7 +5,7 @@ metadata: spec: containers: - name: busybox-cnt01 - image: busybox + image: busybox:1.28 command: ["/bin/sh"] args: ["-c", "while true; do echo hello from cnt01; sleep 10;done"] resources: @@ -16,7 +16,7 @@ spec: memory: "200Mi" cpu: "500m" - name: busybox-cnt02 - image: busybox + image: busybox:1.28 command: ["/bin/sh"] args: ["-c", "while true; do echo hello from cnt02; sleep 10;done"] resources: @@ -24,7 +24,7 @@ spec: memory: "100Mi" cpu: "100m" - name: busybox-cnt03 - image: busybox + image: busybox:1.28 command: ["/bin/sh"] args: ["-c", "while true; do echo hello from cnt03; sleep 10;done"] resources: @@ -32,6 +32,6 @@ spec: memory: "200Mi" cpu: "500m" - name: busybox-cnt04 - image: busybox + image: busybox:1.28 command: ["/bin/sh"] args: ["-c", "while true; do echo hello from cnt04; sleep 10;done"] diff --git a/content/zh/examples/admin/resource/limit-range-pod-3.yaml b/content/zh/examples/admin/resource/limit-range-pod-3.yaml index 8afdb6379c..503200a966 100644 --- a/content/zh/examples/admin/resource/limit-range-pod-3.yaml +++ b/content/zh/examples/admin/resource/limit-range-pod-3.yaml @@ -5,7 +5,7 @@ metadata: spec: containers: - name: busybox-cnt01 - image: busybox + image: busybox:1.28 resources: limits: memory: "300Mi" diff --git a/content/zh/examples/application/job/cronjob.yaml b/content/zh/examples/application/job/cronjob.yaml index 9f06ca7bd6..78d0e2d314 100644 --- a/content/zh/examples/application/job/cronjob.yaml +++ b/content/zh/examples/application/job/cronjob.yaml @@ -10,7 +10,7 @@ spec: spec: containers: - name: hello - image: busybox + image: busybox:1.28 imagePullPolicy: IfNotPresent command: - /bin/sh diff --git a/content/zh/examples/application/job/job-tmpl.yaml b/content/zh/examples/application/job/job-tmpl.yaml index 790025b38b..d7dbbafd62 100644 --- a/content/zh/examples/application/job/job-tmpl.yaml +++ b/content/zh/examples/application/job/job-tmpl.yaml @@ -13,6 +13,6 @@ spec: spec: containers: - name: c - image: busybox + image: busybox:1.28 command: ["sh", "-c", "echo Processing item $ITEM && sleep 5"] restartPolicy: Never diff --git a/content/zh/examples/debug/counter-pod.yaml b/content/zh/examples/debug/counter-pod.yaml index f997886386..a91b2f8915 100644 --- a/content/zh/examples/debug/counter-pod.yaml +++ b/content/zh/examples/debug/counter-pod.yaml @@ -5,6 +5,6 @@ metadata: spec: containers: - name: count - image: busybox + image: busybox:1.28 args: [/bin/sh, -c, 'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done'] diff --git a/content/zh/examples/pods/init-containers.yaml b/content/zh/examples/pods/init-containers.yaml index 667b03eccd..e55895d673 100644 --- a/content/zh/examples/pods/init-containers.yaml +++ b/content/zh/examples/pods/init-containers.yaml @@ -14,7 +14,7 @@ spec: # These containers are run during pod initialization initContainers: - name: install - image: busybox + image: busybox:1.28 command: - wget - "-O" diff --git a/content/zh/examples/pods/inject/dependent-envars.yaml b/content/zh/examples/pods/inject/dependent-envars.yaml index 2509c6f47b..67d07098ba 100644 --- a/content/zh/examples/pods/inject/dependent-envars.yaml +++ b/content/zh/examples/pods/inject/dependent-envars.yaml @@ -10,7 +10,7 @@ spec: command: - sh - -c - image: busybox + image: busybox:1.28 env: - name: SERVICE_PORT value: "80" diff --git a/content/zh/examples/pods/security/hello-apparmor.yaml b/content/zh/examples/pods/security/hello-apparmor.yaml index 3e9b3b2a9c..000645f1c7 100644 --- a/content/zh/examples/pods/security/hello-apparmor.yaml +++ b/content/zh/examples/pods/security/hello-apparmor.yaml @@ -9,5 +9,5 @@ metadata: spec: containers: - name: hello - image: busybox + image: busybox:1.28 command: [ "sh", "-c", "echo 'Hello AppArmor!' && sleep 1h" ] diff --git a/content/zh/examples/pods/security/security-context.yaml b/content/zh/examples/pods/security/security-context.yaml index 35cb1eeebe..7903c39c64 100644 --- a/content/zh/examples/pods/security/security-context.yaml +++ b/content/zh/examples/pods/security/security-context.yaml @@ -12,7 +12,7 @@ spec: emptyDir: {} containers: - name: sec-ctx-demo - image: busybox + image: busybox:1.28 command: [ "sh", "-c", "sleep 1h" ] volumeMounts: - name: sec-ctx-vol diff --git a/content/zh/examples/pods/share-process-namespace.yaml b/content/zh/examples/pods/share-process-namespace.yaml index af812732a2..bd48bf0ff6 100644 --- a/content/zh/examples/pods/share-process-namespace.yaml +++ b/content/zh/examples/pods/share-process-namespace.yaml @@ -8,7 +8,7 @@ spec: - name: nginx image: nginx - name: shell - image: busybox + image: busybox:1.28 securityContext: capabilities: add: diff --git a/content/zh/examples/pods/storage/projected-secret-downwardapi-configmap.yaml b/content/zh/examples/pods/storage/projected-secret-downwardapi-configmap.yaml index 270db99dcd..453dc08c0c 100644 --- a/content/zh/examples/pods/storage/projected-secret-downwardapi-configmap.yaml +++ b/content/zh/examples/pods/storage/projected-secret-downwardapi-configmap.yaml @@ -5,7 +5,7 @@ metadata: spec: containers: - name: container-test - image: busybox + image: busybox:1.28 volumeMounts: - name: all-in-one mountPath: "/projected-volume" diff --git a/content/zh/examples/pods/storage/projected-secrets-nondefault-permission-mode.yaml b/content/zh/examples/pods/storage/projected-secrets-nondefault-permission-mode.yaml index f69b43161e..b921fd93c5 100644 --- a/content/zh/examples/pods/storage/projected-secrets-nondefault-permission-mode.yaml +++ b/content/zh/examples/pods/storage/projected-secrets-nondefault-permission-mode.yaml @@ -5,7 +5,7 @@ metadata: spec: containers: - name: container-test - image: busybox + image: busybox:1.28 volumeMounts: - name: all-in-one mountPath: "/projected-volume" diff --git a/content/zh/examples/pods/storage/projected-service-account-token.yaml b/content/zh/examples/pods/storage/projected-service-account-token.yaml index 3ad06b5dc7..cc307659a7 100644 --- a/content/zh/examples/pods/storage/projected-service-account-token.yaml +++ b/content/zh/examples/pods/storage/projected-service-account-token.yaml @@ -5,7 +5,7 @@ metadata: spec: containers: - name: container-test - image: busybox + image: busybox:1.28 volumeMounts: - name: token-vol mountPath: "/service-account" diff --git a/content/zh/examples/pods/storage/projected.yaml b/content/zh/examples/pods/storage/projected.yaml index 172ca0dee5..4244048eb7 100644 --- a/content/zh/examples/pods/storage/projected.yaml +++ b/content/zh/examples/pods/storage/projected.yaml @@ -5,7 +5,7 @@ metadata: spec: containers: - name: test-projected-volume - image: busybox + image: busybox:1.28 args: - sleep - "86400" diff --git a/content/zh/examples/service/networking/hostaliases-pod.yaml b/content/zh/examples/service/networking/hostaliases-pod.yaml index 643813b34a..268bffbbf5 100644 --- a/content/zh/examples/service/networking/hostaliases-pod.yaml +++ b/content/zh/examples/service/networking/hostaliases-pod.yaml @@ -15,7 +15,7 @@ spec: - "bar.remote" containers: - name: cat-hosts - image: busybox + image: busybox:1.28 command: - cat args: From 9a49299b4f15e54e0957c0681f86abd161a492de Mon Sep 17 00:00:00 2001 From: Ilya Z Date: Sun, 27 Mar 2022 12:20:37 +0400 Subject: [PATCH 062/102] cheatsheet_fixes --- content/ru/docs/reference/kubectl/cheatsheet.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/content/ru/docs/reference/kubectl/cheatsheet.md b/content/ru/docs/reference/kubectl/cheatsheet.md index 02a8a9bc4a..8c4721b4fc 100644 --- a/content/ru/docs/reference/kubectl/cheatsheet.md +++ b/content/ru/docs/reference/kubectl/cheatsheet.md @@ -235,7 +235,7 @@ kubectl get pod mypod -o yaml | sed 's/\(image: myimage\):.*$/\1:v4/' | kubectl kubectl label pods my-pod new-label=awesome # Добавить метку kubectl annotate pods my-pod icon-url=http://goo.gl/XXBTWq # Добавить аннотацию -kubectl autoscale deployment foo --min=2 --max=10 # Автоматически промасштабировать развёртывание "foo" +kubectl autoscale deployment foo --min=2 --max=10 # Автоматически масштабировать развёртывание "foo" в диапазоне от 2 до 10 подов ``` ## Обновление ресурсов @@ -269,10 +269,10 @@ KUBE_EDITOR="nano" kubectl edit svc/docker-registry # Использовать ## Масштабирование ресурсов ```bash -kubectl scale --replicas=3 rs/foo # Промасштабировать набор реплик (replicaset) 'foo' до 3 -kubectl scale --replicas=3 -f foo.yaml # Промасштабировать ресурс в "foo.yaml" до 3 -kubectl scale --current-replicas=2 --replicas=3 deployment/mysql # Если количество реплик в развёртывании mysql равен 2, промасштабировать его до 3 -kubectl scale --replicas=5 rc/foo rc/bar rc/baz # Промасштабировать несколько контроллеров репликации +kubectl scale --replicas=3 rs/foo # Масштабирование набора реплик (replicaset) 'foo' до 3 +kubectl scale --replicas=3 -f foo.yaml # Масштабирование ресурса в "foo.yaml" до 3 +kubectl scale --current-replicas=2 --replicas=3 deployment/mysql # Если количество реплик в развёртывании mysql равен 2, масштабировать его до 3 +kubectl scale --replicas=5 rc/foo rc/bar rc/baz # Масштабирование нескольких контроллеров репликации до 5 ``` ## Удаление ресурсов @@ -362,7 +362,7 @@ kubectl api-resources --api-group=extensions # Все ресурсы в API-гр ### Уровни детальности вывода и отладки в Kubectl -Уровни детальности вывода Kubectl регулируются с помощью флагов `-v` или `--v`, за которыми следует целое число, представляющее уровни логирования. Общие соглашения по логированиия Kubernetes и связанные с ними уровни описаны [здесь](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/logging.md). +Уровни детальности вывода Kubectl регулируются с помощью флагов `-v` или `--v`, за которыми следует целое число, представляющее уровни логирования. Общие соглашения по логированию Kubernetes и связанные с ними уровни описаны [здесь](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/logging.md). Уровень детальности | Описание From 482bfee980bb62774cc778de184c47c6d42e657e Mon Sep 17 00:00:00 2001 From: Ilya Z Date: Sun, 27 Mar 2022 12:47:02 +0400 Subject: [PATCH 063/102] kubectl_docs_fixes --- .../kubectl/docker-cli-to-kubectl.md | 2 +- content/ru/docs/reference/kubectl/jsonpath.md | 2 +- content/ru/docs/reference/kubectl/kubectl.md | 94 +++++++++---------- 3 files changed, 49 insertions(+), 49 deletions(-) diff --git a/content/ru/docs/reference/kubectl/docker-cli-to-kubectl.md b/content/ru/docs/reference/kubectl/docker-cli-to-kubectl.md index 4d834098c6..c742e1fba4 100644 --- a/content/ru/docs/reference/kubectl/docker-cli-to-kubectl.md +++ b/content/ru/docs/reference/kubectl/docker-cli-to-kubectl.md @@ -70,7 +70,7 @@ kubectl run [-i] [--tty] --attach --image= ``` В отличие от `docker run ...`, если вы укажете `--attach`, то присоедините `stdin`, `stdout` and `stderr`. Нельзя проконтролировать, какие потоки прикрепляются (`docker -a ...`). -Чтобы отсоединиться от контейнера воспользуетесь комбинацией клавиш Ctrl+P, а затем Ctrl+Q. +Чтобы отсоединиться от контейнера, воспользуетесь комбинацией клавиш Ctrl+P, а затем Ctrl+Q. Так как команда kubectl run запускает развёртывание для контейнера, то оно начнет перезапускаться, если завершить прикрепленный процесс по нажатию Ctrl+C, в отличие от команды `docker run -it`. Для удаления объекта Deployment вместе с подами, необходимо выполнить команду `kubectl delete deployment `. diff --git a/content/ru/docs/reference/kubectl/jsonpath.md b/content/ru/docs/reference/kubectl/jsonpath.md index d6bd9b5c48..231d3a0dc9 100644 --- a/content/ru/docs/reference/kubectl/jsonpath.md +++ b/content/ru/docs/reference/kubectl/jsonpath.md @@ -90,7 +90,7 @@ kubectl get pods -o=jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.st ``` {{< note >}} -В Windows нужно заключить в _двойные_ кавычки JSONPath-шаблон, который содержит пробелы (не в одинарные, как в примерах выше для bash). Таким образом, любые литералы в таких шаблонов нужно оборачивать в одинарные кавычки или экранированные двойные кавычки. Например: +В Windows нужно заключить в _двойные_ кавычки JSONPath-шаблон, который содержит пробелы (не в одинарные, как в примерах выше для bash). Таким образом, любые литералы в таких шаблонах нужно оборачивать в одинарные кавычки или экранированные двойные кавычки. Например: ```cmd kubectl get pods -o=jsonpath="{range .items[*]}{.metadata.name}{'\t'}{.status.startTime}{'\n'}{end}" diff --git a/content/ru/docs/reference/kubectl/kubectl.md b/content/ru/docs/reference/kubectl/kubectl.md index ce01d0b8ab..405522525d 100644 --- a/content/ru/docs/reference/kubectl/kubectl.md +++ b/content/ru/docs/reference/kubectl/kubectl.md @@ -158,14 +158,14 @@ kubectl [flags]
- + - + @@ -221,7 +221,7 @@ kubectl [flags] - + @@ -277,7 +277,7 @@ kubectl [flags] - + @@ -333,7 +333,7 @@ kubectl [flags] - + @@ -521,48 +521,48 @@ kubectl [flags] ## {{% heading "seealso" %}} -* [kubectl annotate](/docs/reference/generated/kubectl/kubectl-commands#annotate) - Обновить аннотации ресурса -* [kubectl api-resources](/docs/reference/generated/kubectl/kubectl-commands#api-resources) - Вывести доступные API-ресурсы на сервере -* [kubectl api-versions](/docs/reference/generated/kubectl/kubectl-commands#api-versions) - Вывести доступные API-версии на сервере в виде "group/version". -* [kubectl apply](/docs/reference/generated/kubectl/kubectl-commands#apply) - Внести изменения в конфигурацию ресурса из файла или потока stdin. -* [kubectl attach](/docs/reference/generated/kubectl/kubectl-commands#attach) - Присоединиться к запущенному контейнеру -* [kubectl auth](/docs/reference/generated/kubectl/kubectl-commands#auth) - Проверить разрешение на выполнение определённых действий -* [kubectl autoscale](/docs/reference/generated/kubectl/kubectl-commands#autoscale) - Автоматически промасштабировать Deployment, ReplicaSet или ReplicationController -* [kubectl certificate](/docs/reference/generated/kubectl/kubectl-commands#certificate) - Изменить сертификаты ресурсов. -* [kubectl cluster-info](/docs/reference/generated/kubectl/kubectl-commands#cluster-info) - Показать информацию по кластеру -* [kubectl completion](/docs/reference/generated/kubectl/kubectl-commands#completion) - Вывод кода автодополнения указанной командной оболочки (bash или zsh) -* [kubectl config](/docs/reference/generated/kubectl/kubectl-commands#config) - Изменить файлы kubeconfig -* [kubectl convert](/docs/reference/generated/kubectl/kubectl-commands#convert) - Конвертировать конфигурационные файлы в различные API-версии -* [kubectl cordon](/docs/reference/generated/kubectl/kubectl-commands#cordon) - Отметить узел как неназначаемый -* [kubectl cp](/docs/reference/generated/kubectl/kubectl-commands#cp) - Копировать файлы и директории в/из контейнеров. -* [kubectl create](/docs/reference/generated/kubectl/kubectl-commands#create) - Создать ресурс из файла или потока stdin. -* [kubectl delete](/docs/reference/generated/kubectl/kubectl-commands#delete) - Удалить ресурсы из файла, потока stdin, либо с помощью селекторов меток, имен, селекторов ресурсов или ресурсов -* [kubectl describe](/docs/reference/generated/kubectl/kubectl-commands#describe) - Показать подробную информацию о конкретном ресурсе или группе ресурсов -* [kubectl diff](/docs/reference/generated/kubectl/kubectl-commands#diff) - Сравнить действующую версию с новой (применяемой) -* [kubectl drain](/docs/reference/generated/kubectl/kubectl-commands#drain) - Вытеснить узел для подготовки к эксплуатации -* [kubectl edit](/docs/reference/generated/kubectl/kubectl-commands#edit) - Отредактировать ресурс на сервере -* [kubectl exec](/docs/reference/generated/kubectl/kubectl-commands#exec) - Выполнить команду в контейнере -* [kubectl explain](/docs/reference/generated/kubectl/kubectl-commands#explain) - Получить документацию ресурсов -* [kubectl expose](/docs/reference/generated/kubectl/kubectl-commands#expose) - Создать новый сервис Kubernetes из контроллера репликации, сервиса, развёртывания или пода -* [kubectl get](/docs/reference/generated/kubectl/kubectl-commands#get) - Вывести один или несколько ресурсов -* [kubectl kustomize](/docs/reference/generated/kubectl/kubectl-commands#kustomize) - Собрать ресурсы kustomization из директории или URL-адреса. -* [kubectl label](/docs/reference/generated/kubectl/kubectl-commands#label) - Обновить метки ресурса -* [kubectl logs](/docs/reference/generated/kubectl/kubectl-commands#logs) - Вывести логи контейнера в поде -* [kubectl options](/docs/reference/generated/kubectl/kubectl-commands#options) - Вывести список флагов, применяемых ко всем командам -* [kubectl patch](/docs/reference/generated/kubectl/kubectl-commands#patch) - Обновить один или несколько полей ресурса, используя стратегию слияния патча -* [kubectl plugin](/docs/reference/generated/kubectl/kubectl-commands#plugin) - Команда для работы с плагинами. -* [kubectl port-forward](/docs/reference/generated/kubectl/kubectl-commands#port-forward) - Переадресовать один или несколько локальных портов в под -* [kubectl proxy](/docs/reference/generated/kubectl/kubectl-commands#proxy) - Запустить прокси на API-сервер Kubernetes -* [kubectl replace](/docs/reference/generated/kubectl/kubectl-commands#replace) - Заменить ресурс из определения в файле или потоке stdin. -* [kubectl rollout](/docs/reference/generated/kubectl/kubectl-commands#rollout) - Управление плавающим обновлением ресурса -* [kubectl run](/docs/reference/generated/kubectl/kubectl-commands#run) - Запустить указанный образ в кластере -* [kubectl scale](/docs/reference/generated/kubectl/kubectl-commands#scale) - Задать новый размер для Deployment, ReplicaSet или Replication Controller. -* [kubectl set](/docs/reference/generated/kubectl/kubectl-commands#set) - Конфигурировать ресурсы в объектах -* [kubectl taint](/docs/reference/generated/kubectl/kubectl-commands#taint) - Обновить ограничения для одного или нескольких узлов -* [kubectl top](/docs/reference/generated/kubectl/kubectl-commands#top) - Показать информацию по использованию системных ресурсов (процессор, память, диск) -* [kubectl uncordon](/docs/reference/generated/kubectl/kubectl-commands#uncordon) - Отметить узел как назначаемый -* [kubectl version](/docs/reference/generated/kubectl/kubectl-commands#version) - Вывести информацию о версии клиента и сервера -* [kubectl wait](/docs/reference/generated/kubectl/kubectl-commands#wait) - Экспериментально: ожидать выполнения определенного условия в одном или нескольких ресурсах. +* [kubectl annotate](/docs/reference/generated/kubectl/kubectl-commands#annotate) - Обновить аннотации ресурса. +* [kubectl api-resources](/docs/reference/generated/kubectl/kubectl-commands#api-resources) - Вывести доступные API-ресурсы на сервере. +* [kubectl api-versions](/docs/reference/generated/kubectl/kubectl-commands#api-versions) - Вывести доступные API-версии на сервере в виде "group/version". +* [kubectl apply](/docs/reference/generated/kubectl/kubectl-commands#apply) - Внести изменения в конфигурацию ресурса из файла или потока stdin. +* [kubectl attach](/docs/reference/generated/kubectl/kubectl-commands#attach) - Присоединиться к запущенному контейнеру. +* [kubectl auth](/docs/reference/generated/kubectl/kubectl-commands#auth) - Проверить разрешение на выполнение определённых действий. +* [kubectl autoscale](/docs/reference/generated/kubectl/kubectl-commands#autoscale) - Автоматически масштабировать Deployment, ReplicaSet или ReplicationController. +* [kubectl certificate](/docs/reference/generated/kubectl/kubectl-commands#certificate) - Изменить сертификаты ресурсов. +* [kubectl cluster-info](/docs/reference/generated/kubectl/kubectl-commands#cluster-info) - Показать информацию по кластеру. +* [kubectl completion](/docs/reference/generated/kubectl/kubectl-commands#completion) - Вывод кода автодополнения указанной командной оболочки (bash или zsh). +* [kubectl config](/docs/reference/generated/kubectl/kubectl-commands#config) - Изменить файлы kubeconfig. +* [kubectl convert](/docs/reference/generated/kubectl/kubectl-commands#convert) - Конвертировать конфигурационные файлы в различные API-версии. +* [kubectl cordon](/docs/reference/generated/kubectl/kubectl-commands#cordon) - Отметить узел как неназначаемый. +* [kubectl cp](/docs/reference/generated/kubectl/kubectl-commands#cp) - Копировать файлы и директории в/из контейнеров. +* [kubectl create](/docs/reference/generated/kubectl/kubectl-commands#create) - Создать ресурс из файла или потока stdin. +* [kubectl delete](/docs/reference/generated/kubectl/kubectl-commands#delete) - Удалить ресурсы из файла, потока stdin, либо с помощью селекторов меток, имен, селекторов ресурсов или ресурсов. +* [kubectl describe](/docs/reference/generated/kubectl/kubectl-commands#describe) - Показать подробную информацию о конкретном ресурсе или группе ресурсов. +* [kubectl diff](/docs/reference/generated/kubectl/kubectl-commands#diff) - Сравнить действующую версию с новой (применяемой). +* [kubectl drain](/docs/reference/generated/kubectl/kubectl-commands#drain) - Вытеснить узел для подготовки к эксплуатации. +* [kubectl edit](/docs/reference/generated/kubectl/kubectl-commands#edit) - Отредактировать ресурс на сервере. +* [kubectl exec](/docs/reference/generated/kubectl/kubectl-commands#exec) - Выполнить команду в контейнере. +* [kubectl explain](/docs/reference/generated/kubectl/kubectl-commands#explain) - Получить документацию ресурсов. +* [kubectl expose](/docs/reference/generated/kubectl/kubectl-commands#expose) - Создать новый сервис Kubernetes из контроллера репликации, сервиса, развёртывания или пода. +* [kubectl get](/docs/reference/generated/kubectl/kubectl-commands#get) - Вывести один или несколько ресурсов. +* [kubectl kustomize](/docs/reference/generated/kubectl/kubectl-commands#kustomize) - Собрать ресурсы kustomization из директории или URL-адреса. +* [kubectl label](/docs/reference/generated/kubectl/kubectl-commands#label) - Обновить метки ресурса. +* [kubectl logs](/docs/reference/generated/kubectl/kubectl-commands#logs) - Вывести логи контейнера в поде. +* [kubectl options](/docs/reference/generated/kubectl/kubectl-commands#options) - Вывести список флагов, применяемых ко всем командам. +* [kubectl patch](/docs/reference/generated/kubectl/kubectl-commands#patch) - Обновить один или несколько полей ресурса, используя стратегию слияния патча. +* [kubectl plugin](/docs/reference/generated/kubectl/kubectl-commands#plugin) - Команда для работы с плагинами. +* [kubectl port-forward](/docs/reference/generated/kubectl/kubectl-commands#port-forward) - Переадресовать один или несколько локальных портов в под. +* [kubectl proxy](/docs/reference/generated/kubectl/kubectl-commands#proxy) - Запустить прокси на API-сервер Kubernetes. +* [kubectl replace](/docs/reference/generated/kubectl/kubectl-commands#replace) - Заменить ресурс из определения в файле или потоке stdin. +* [kubectl rollout](/docs/reference/generated/kubectl/kubectl-commands#rollout) - Управление плавающим обновлением ресурса. +* [kubectl run](/docs/reference/generated/kubectl/kubectl-commands#run) - Запустить указанный образ в кластере. +* [kubectl scale](/docs/reference/generated/kubectl/kubectl-commands#scale) - Задать новый размер для Deployment, ReplicaSet или Replication Controller. +* [kubectl set](/docs/reference/generated/kubectl/kubectl-commands#set) - Конфигурировать ресурсы в объектах. +* [kubectl taint](/docs/reference/generated/kubectl/kubectl-commands#taint) - Обновить ограничения для одного или нескольких узлов. +* [kubectl top](/docs/reference/generated/kubectl/kubectl-commands#top) - Показать информацию по использованию системных ресурсов (процессор, память, диск). +* [kubectl uncordon](/docs/reference/generated/kubectl/kubectl-commands#uncordon) - Отметить узел как назначаемый. +* [kubectl version](/docs/reference/generated/kubectl/kubectl-commands#version) - Вывести информацию о версии клиента и сервера. +* [kubectl wait](/docs/reference/generated/kubectl/kubectl-commands#wait) - Экспериментально: ожидать выполнения определенного условия в одном или нескольких ресурсах. From 81881f8d8452ac2ab30f3f708e6149c1fc8630e7 Mon Sep 17 00:00:00 2001 From: Sudheer Satyanarayana Date: Sun, 27 Mar 2022 16:01:25 +0530 Subject: [PATCH 064/102] minor text edit `Pay attention to the case of suffixes` seems better than `Take care about case for suffixes` --- .../docs/concepts/configuration/manage-resources-containers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/concepts/configuration/manage-resources-containers.md b/content/en/docs/concepts/configuration/manage-resources-containers.md index 18f2fc5cb5..575f96f04d 100644 --- a/content/en/docs/concepts/configuration/manage-resources-containers.md +++ b/content/en/docs/concepts/configuration/manage-resources-containers.md @@ -134,7 +134,7 @@ Mi, Ki. For example, the following represent roughly the same value: 128974848, 129e6, 129M, 128974848000m, 123Mi ``` -Take care about case for suffixes. If you request `400m` of memory, this is a request +Pay attention to the case of the suffixes. If you request `400m` of memory, this is a request for 0.4 bytes. Someone who types that probably meant to ask for 400 mebibytes (`400Mi`) or 400 megabytes (`400M`). From f01be79f66100ad40eca6490b3f7a90ba78570f6 Mon Sep 17 00:00:00 2001 From: Qiming Teng Date: Sun, 27 Mar 2022 19:43:59 +0800 Subject: [PATCH 065/102] [zh] Resync pod topology spread constraints page --- .../pods/pod-topology-spread-constraints.md | 140 ++++++++++-------- 1 file changed, 76 insertions(+), 64 deletions(-) diff --git a/content/zh/docs/concepts/workloads/pods/pod-topology-spread-constraints.md b/content/zh/docs/concepts/workloads/pods/pod-topology-spread-constraints.md index 5ac4fed192..77e2127443 100644 --- a/content/zh/docs/concepts/workloads/pods/pod-topology-spread-constraints.md +++ b/content/zh/docs/concepts/workloads/pods/pod-topology-spread-constraints.md @@ -75,7 +75,7 @@ node4 Ready 2m43s v1.16.0 node=node4,zone=zoneB -然后从逻辑上看集群如下: +那么,从逻辑上看集群如下: {{}} graph TB @@ -96,11 +96,9 @@ graph TB {{< /mermaid >}} -你可以复用在大多数集群上自动创建和填充的 -[常用标签](/zh/docs/reference/labels-annotations-taints/), +你可以复用在大多数集群上自动创建和填充的[常用标签](/zh/docs/reference/labels-annotations-taints/), 而不是手动添加标签。 +当 Pod 定义了不止一个 `topologySpreadConstraint`,这些约束之间是逻辑与的关系。 +kube-scheduler 会为新的 Pod 寻找一个能够满足所有约束的节点。 + @@ -353,7 +357,6 @@ graph BT class zoneA,zoneB cluster; {{< /mermaid >}} - @@ -374,54 +377,59 @@ The scheduler will skip the non-matching nodes from the skew calculations if the --> ### 节点亲和性与节点选择器的相互作用 {#interaction-with-node-affinity-and-node-selectors} -如果 Pod 定义了 `spec.nodeSelector` 或 `spec.affinity.nodeAffinity`,调度器将从倾斜计算中跳过不匹配的节点。 +如果 Pod 定义了 `spec.nodeSelector` 或 `spec.affinity.nodeAffinity`, +调度器将在偏差计算中跳过不匹配的节点。 - 假设你有一个跨越 zoneA 到 zoneC 的 5 节点集群: +### 示例:TopologySpreadConstraints 与 NodeAffinity - {{}} - graph BT - subgraph "zoneB" - p3(Pod) --> n3(Node3) - n4(Node4) - end - subgraph "zoneA" - p1(Pod) --> n1(Node1) - p2(Pod) --> n2(Node2) - end +假设你有一个跨越 zoneA 到 zoneC 的 5 节点集群: - classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000; - classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff; - classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5; - class n1,n2,n3,n4,p1,p2,p3 k8s; - class p4 plain; - class zoneA,zoneB cluster; - {{< /mermaid >}} +{{}} +graph BT + subgraph "zoneB" + p3(Pod) --> n3(Node3) + n4(Node4) + end + subgraph "zoneA" + p1(Pod) --> n1(Node1) + p2(Pod) --> n2(Node2) + end - {{}} - graph BT - subgraph "zoneC" - n5(Node5) - end +classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000; +classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff; +classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5; +class n1,n2,n3,n4,p1,p2,p3 k8s; +class p4 plain; +class zoneA,zoneB cluster; +{{< /mermaid >}} - classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000; - classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff; - classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5; - class n5 k8s; - class zoneC cluster; - {{< /mermaid >}} +{{}} +graph BT + subgraph "zoneC" + n5(Node5) + end - 而且你知道 "zoneC" 必须被排除在外。在这种情况下,可以按如下方式编写 yaml, - 以便将 "mypod" 放置在 "zoneB" 上,而不是 "zoneC" 上。同样,`spec.nodeSelector` - 也要一样处理。 +classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000; +classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff; +classDef cluster fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5; +class n5 k8s; +class zoneC cluster; +{{< /mermaid >}} - {{< codenew file="pods/topology-spread-constraints/one-constraint-with-nodeaffinity.yaml" >}} + + +而且你知道 "zoneC" 必须被排除在外。在这种情况下,可以按如下方式编写 YAML, +以便将 "mypod" 放置在 "zoneB" 上,而不是 "zoneC" 上。同样,`spec.nodeSelector` +也要一样处理。 + +{{< codenew file="pods/topology-spread-constraints/one-constraint-with-nodeaffinity.yaml" >}} 此外,原来用于提供等同行为的 `SelectorSpread` 插件也会被禁用。 +{{< note >}} + +对于分布约束中所指定的拓扑键而言,`PodTopologySpread` 插件不会为不包含这些主键的节点评分。 +这可能导致在使用默认拓扑约束时,其行为与原来的 `SelectorSpread` 插件的默认行为不同, + -{{< note >}} 如果你的节点不会 **同时** 设置 `kubernetes.io/hostname` 和 `topology.kubernetes.io/zone` 标签,你应该定义自己的约束而不是使用 Kubernetes 的默认约束。 - -插件 `PodTopologySpread` 不会为未设置分布约束中所给拓扑键的节点评分。 {{< /note >}} -如果你不想为集群使用默认的 Pod 分布约束,你可以通过设置 `defaultingType` 参数为 `List` 和 -将 `PodTopologySpread` 插件配置中的 `defaultConstraints` 参数置空来禁用默认 Pod 分布约束。 +如果你不想为集群使用默认的 Pod 分布约束,你可以通过设置 `defaultingType` 参数为 `List` +并将 `PodTopologySpread` 插件配置中的 `defaultConstraints` 参数置空来禁用默认 Pod 分布约束。 ```yaml -apiVersion: kubescheduler.config.k8s.io/v1beta1 +apiVersion: kubescheduler.config.k8s.io/v1beta3 kind: KubeSchedulerConfiguration profiles: @@ -613,9 +625,9 @@ scheduled - more packed or more scattered. - 对于 `PodAffinity`,你可以尝试将任意数量的 Pod 集中到符合条件的拓扑域中。 - 对于 `PodAntiAffinity`,只能将一个 Pod 调度到某个拓扑域中。 @@ -627,12 +639,6 @@ cost-saving. This can also help on rolling update workloads and scaling out replicas smoothly. See [Motivation](https://github.com/kubernetes/enhancements/tree/master/keps/sig-scheduling/895-pod-topology-spread#motivation) for more details. - - -The "EvenPodsSpread" feature provides flexible options to distribute Pods evenly across different -topology domains - to achieve high availability or cost-saving. This can also help on rolling update -workloads and scaling out replicas smoothly. -See [Motivation](https://github.com/kubernetes/enhancements/blob/master/keps/sig-scheduling/20190221-pod-topology-spread.md#motivation) for more details. --> 要实现更细粒度的控制,你可以设置拓扑分布约束来将 Pod 分布到不同的拓扑域下, 从而实现高可用性或节省成本。这也有助于工作负载的滚动更新和平稳地扩展副本规模。 @@ -642,13 +648,19 @@ See [Motivation](https://github.com/kubernetes/enhancements/blob/master/keps/sig ## 已知局限性 -- Deployment 缩容操作可能导致 Pod 分布不平衡。 -- 具有污点的节点上的 Pods 也会被统计。 +- 当 Pod 被移除时,无法保证约束仍被满足。例如,缩减某 Deployment 的规模时, + Pod 的分布可能不再均衡。 + 你可以使用 [Descheduler](https://github.com/kubernetes-sigs/descheduler) + 来重新实现 Pod 分布的均衡。 + +- 具有污点的节点上匹配的 Pods 也会被统计。 参考 [Issue 80921](https://github.com/kubernetes/kubernetes/issues/80921)。 ## {{% heading "whatsnext" %}} From 27ba7df7b2491829a55cb7c0b01ca10fc3093d73 Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Sun, 27 Mar 2022 20:58:47 +0800 Subject: [PATCH 066/102] [zh] Update update-daemon-set.md Signed-off-by: xin.li --- content/zh/docs/tasks/manage-daemon/update-daemon-set.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/content/zh/docs/tasks/manage-daemon/update-daemon-set.md b/content/zh/docs/tasks/manage-daemon/update-daemon-set.md index f36583c90c..ee8bc83eaf 100644 --- a/content/zh/docs/tasks/manage-daemon/update-daemon-set.md +++ b/content/zh/docs/tasks/manage-daemon/update-daemon-set.md @@ -62,17 +62,17 @@ To enable the rolling update feature of a DaemonSet, you must set its 你可能想设置 -[`.spec.updateStrategy.rollingUpdate.maxUnavailable`](/zh/docs/concepts/workloads/controllers/deployment/#max-unavailable) (默认为 1), -[`.spec.minReadySeconds`](/zh/docs/concepts/workloads/controllers/deployment/#min-ready-seconds) (默认为 0) 和 +[`.spec.updateStrategy.rollingUpdate.maxUnavailable`](/zh/docs/reference/kubernetes-api/workload-resources/daemon-set-v1/#DaemonSetSpec) (默认为 1), +[`.spec.minReadySeconds`](/zh/docs/reference/kubernetes-api/workload-resources/daemon-set-v1/#DaemonSetSpec) (默认为 0) 和 [`.spec.updateStrategy.rollingUpdate.maxSurge`](/zh/docs/reference/kubernetes-api/workload-resources/daemon-set-v1/#DaemonSetSpec) (一种 Beta 阶段的特性,默认为 0)。 From 10ff885b1ca5f554a89498b8799c2a1df0c99e1a Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Sun, 27 Mar 2022 21:02:03 +0800 Subject: [PATCH 067/102] [zh] Update update-api-object-kubectl-patch.md Signed-off-by: xin.li --- .../update-api-object-kubectl-patch.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/content/zh/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch.md b/content/zh/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch.md index a06cfa828b..a5c7cd9452 100644 --- a/content/zh/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch.md +++ b/content/zh/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch.md @@ -283,13 +283,11 @@ containers: name: patch-demo-ctr ... ``` -```shell - - +```yaml tolerations: - - effect: NoSchedule - key: disktype - value: ssd + - effect: NoSchedule + key: disktype + value: ssd ``` ## 创建 PDB 对象 -你可以通过类似 `kubectl apply -f mypdb.yaml` 的命令来创建 PDB。 +你可以使用 kubectl 创建或更新 PDB 对象。 +```shell +kubectl apply -f mypdb.yaml +``` + + +**作者和采访者:** +[Anubhav Vardhan](https://github.com/anubha-v-ardhan), +[Atharva Shinde](https://github.com/Atharva-Shinde), +[Avinesh Tripathi](https://github.com/AvineshTripathi), +[Brad McCoy](https://github.com/bradmccoydev), +[Debabrata Panigrahi](https://github.com/Debanitrkl), +[Jayesh Srivastava](https://github.com/jayesh-srivastava), +[Kunal Verma](https://github.com/verma-kunal), +[Pranshu Srivastava](https://github.com/PranshuSrivastava), +[Priyanka Saggu](github.com/Priyankasaggu11929/), +[Purneswar Prasad](https://github.com/PurneswarPrasad), +[Vedant Kakde](https://github.com/vedant-kakde) + +--- + + +大家好👋 + + +欢迎来到亚太地区的”认识我们的贡献者”博文系列第二期。 + + +这篇文章将介绍来自澳大利亚和新西兰地区的四位杰出贡献者, +他们在上游 Kubernetes 项目中承担着不同子项目的领导者和社区贡献者的角色。 + + +闲话少说,让我们直接进入主题。 + +## [Caleb Woodbine](https://github.com/BobyMCbobs) + + +Caleb Woodbine 目前是 ii.nz 组织的成员。 + + +他于 2018 年作为 Kubernetes Conformance 工作组的成员开始为 Kubernetes 项目做贡献。 +他积极向上,他从一位来自新西兰的贡献者 [Hippie Hacker](https://github.com/hh) 的早期指导中受益匪浅。 + + +他在 `SIG k8s-infra` 和 `k8s-conformance` 工作组为 Kubernetes 项目做出了重大贡献。 + + +Caleb 也是 [CloudNative NZ](https://www.meetup.com/cloudnative-nz/) +社区活动的联合组织者,该活动旨在扩大 Kubernetes 项目在整个新西兰的影响力,以鼓励科技教育和改善就业机会。 + + +> _亚太地区需要更多的外联活动,教育工作者和大学必须学习 Kubernetes,因为他们非常缓慢, +而且已经落后了8年多。新西兰倾向于在海外付费,而不是教育当地人最新的云技术。_ + +## [Dylan Graham](https://github.com/DylanGraham) + + +Dylan Graham 是来自澳大利亚 Adeliade 的云计算工程师。自 2018 年以来,他一直在为上游 Kubernetes 项目做出贡献。 + + +他表示,成为如此大项目的一份子,最初压力是比较大的,但社区的友好和开放帮助他度过了难关。 + + +开始在项目文档方面做贡献,现在主要致力于为亚太地区提供社区支持。 + + +他相信,持续参加社区/项目会议,承担项目任务,并在需要时寻求社区指导,可以帮助有抱负的新开发人员成为有效的贡献者。 + + +> _成为大社区的一份子感觉真的很特别。我遇到了一些了不起的人,甚至是在现实生活中疫情发生之前。_ + +## [Hippie Hacker](https://github.com/hh) + + +Hippie 来自新西兰,曾在 CNCF.io 作为战略计划承包商工作 5 年多。他是 k8s-infra、 +API 一致性测试、云提供商一致性提交以及上游 Kubernetes 和 CNCF 项目 apisnoop.cncf.io 域的积极贡献者。 + + +他讲述了他们早期参与 Kubernetes 项目的情况,该项目始于大约 5 年前,当时他们的公司 ii.nz +演示了[使用 PXE 从 Raspberry Pi 启动网络,并在集群中运行Gitlab,以便在服务器上安装 Kubernetes ](https://ii.nz/post/bringing-the-cloud-to-your-community/) + + +他描述了自己的贡献经历:一开始,他试图独自完成所有艰巨的任务,但最终看到了团队协作贡献的好处, +分工合作减少了过度疲劳,这让人们能够凭借自己的动力继续前进。 + + +他建议新的贡献者结对编程。 + + +> _针对一个项目,多人关注和交叉交流往往比单独的评审、批准 PR 能产生更大的效果。_ + +## [Nick Young](https://github.com/youngnick) + + +Nick Young 在 VMware 工作,是 CNCF 入口控制器 Contour 的技术负责人。 +他从一开始就积极参与上游 Kubernetes 项目,最终成为 LTS 工作组的主席, +他提倡关注用户。他目前是 SIG Network Gateway API 子项目的维护者。 + + +他的贡献之路是引人注目的,因为他很早就在 Kubernetes 项目的主要领域工作,这改变了他的轨迹。 + + +他断言,一个新贡献者能做的最好的事情就是“开始贡献”。当然,如果与他的工作息息相关,那好极了; +然而,把非工作时间投入到贡献中去,从长远来看可以在工作上获得回报。 +他认为,应该鼓励新的贡献者,特别是那些目前是 Kubernetes 用户的人,参与到更高层次的项目讨论中来。 + + +> _只要积极主动,做出贡献,你就可以走很远。一旦你活跃了一段时间,你会发现你能够解答别人的问题, +这意味着会有人请教你或和你讨论,在你意识到这一点之前,你就已经是专家了。_ + +--- + + +如果你对我们接下来应该采访的人有任何意见/建议,请在 #sig-contribex 中告知我们。 +非常感谢你的建议。我们很高兴有更多的人帮助我们接触到社区中更优秀的人。 + + +我们下期再见。祝你有个愉快的贡献之旅!👋 From 99b0fce444787ee8d7acc3615a266e9657ea8028 Mon Sep 17 00:00:00 2001 From: zhangxiaoyang Date: Sat, 26 Mar 2022 15:29:21 +0800 Subject: [PATCH 070/102] [zh]Add 2021-12-08-dual-stack-networking-ga.md --- .../2021-12-08-dual-stack-networking-ga.md | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 content/zh/blog/_posts/2021-12-08-dual-stack-networking-ga.md diff --git a/content/zh/blog/_posts/2021-12-08-dual-stack-networking-ga.md b/content/zh/blog/_posts/2021-12-08-dual-stack-networking-ga.md new file mode 100644 index 0000000000..fa8cd74cc0 --- /dev/null +++ b/content/zh/blog/_posts/2021-12-08-dual-stack-networking-ga.md @@ -0,0 +1,154 @@ +--- +layout: blog +title: 'Kubernetes 1.23:IPv4/IPv6 双协议栈网络达到 GA' +date: 2021-12-08 +slug: dual-stack-networking-ga +--- + + + +**作者:** Bridget Kromhout (微软) + + +“Kubernetes 何时支持 IPv6?” 自从 k8s v1.9 版本中首次添加对 IPv6 的 alpha 支持以来,这个问题的讨论越来越频繁。 +虽然 Kubernetes 从 v1.18 版本开始就支持纯 IPv6 集群,但当时还无法支持 IPv4 迁移到 IPv6。 +[IPv4/IPv6 双协议栈网络](https://github.com/kubernetes/enhancements/tree/master/keps/sig-network/563-dual-stack/) +在 Kubernetes v1.23 版本中进入正式发布(GA)阶段。 + +让我们来看看双协议栈网络对你来说意味着什么? + + +## 更新 Service API + + +[Services](/zh/docs/concepts/services-networking/service/) 在 1.20 版本之前是单协议栈的, +因此,使用两个 IP 协议族意味着需为每个 IP 协议族创建一个 Service。在 1.20 版本中对用户体验进行简化, +重新实现了 Service 以支持两个 IP 协议族,这意味着一个 Service 就可以处理 IPv4 和 IPv6 协议。 +对于 Service 而言,任意的 IPv4 和 IPv6 协议组合都可以实现负载均衡。 + + +Service API 现在有了支持双协议栈的新字段,取代了单一的 ipFamily 字段。 +* 你可以通过将 `ipFamilyPolicy` 字段设置为 `SingleStack`、`PreferDualStack` 或 +`RequireDualStack` 来设置 IP 协议族。Service 可以在单协议栈和双协议栈之间进行转换(在某些限制内)。 +* 设置 `ipFamilies` 为指定的协议族列表,可用来设置使用协议族的顺序。 +* 'clusterIPs' 的能力在涵盖了之前的 'clusterIP'的情况下,还允许设置多个 IP 地址。 +所以不再需要运行重复的 Service,在两个 IP 协议族中各运行一个。你可以在两个 IP 协议族中分配集群 IP 地址。 + + +请注意,Pods 也是双协议栈的。对于一个给定的 Pod,不可能在同一协议族中设置多个 IP 地址。 + + +## 默认行为仍然是单协议栈 + + +从 1.20 版本开始,重新实现的双协议栈服务处于 Alpha 阶段,无论集群是否配置了启用双协议栈的特性标志, +Kubernetes 的底层网络都已经包括了双协议栈。 + + +Kubernetes 1.23 删除了这个特性标志,说明该特性已经稳定。 +如果你想要配置双协议栈网络,这一能力总是存在的。 +你可以将集群网络设置为 IPv4 单协议栈 、IPv6 单协议栈或 IPV4/IPV6 双协议栈 。 + + +虽然 Service 是根据你的配置设置的,但 Pod 默认是由 CNI 插件设置的。 +如果你的 CNI 插件分配单协议栈 IP,那么就是单协议栈,除非 `ipFamilyPolicy` 设置为 `PreferDualStack` 或 `RequireDualStack`。 +如果你的 CNI 插件分配双协议栈 IP,则 `pod.status.PodIPs` 默认为双协议栈。 + + +尽管双协议栈是可用的,但并不强制你使用它。 +在[双协议栈服务配置](/zh/docs/concepts/services-networking/dual-stack/#dual-stack-service-configuration-scenarios) +文档中的示例列出了可能出现的各种场景. + + +## 现在尝试双协议栈 + + +虽然现在上游 Kubernetes 支持[双协议栈网络](/zh/docs/concepts/services-networking/dual-stack/) +作为 GA 或稳定特性,但每个提供商对双协议栈 Kubernetes 的支持可能会有所不同。节点需要提供可路由的 IPv4/IPv6 网络接口。 +Pod 需要是双协议栈的。[网络插件](/zh/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/) +是用来为 Pod 分配 IP 地址的,所以集群需要支持双协议栈的网络插件。一些容器网络接口(CNI)插件支持双协议栈,例如 kubenet。 + + +支持双协议栈的生态系统在不断壮大;你可以使用 +[kubeadm 创建双协议栈集群](/zh/docs/setup/production-environment/tools/kubeadm/dual-stack-support/), +在本地尝试用 [KIND 创建双协议栈集群](https://kind.sigs.k8s.io/docs/user/configuration/#ip-family), +还可以将双协议栈集群部署到云上(在查阅 CNI 或 kubenet 可用性的文档之后) + + +## 加入 Network SIG + + +SIG-Network 希望从双协议栈网络的社区体验中学习,以了解更多不断变化的需求和你的用例信息。 +[SIG-network 更新了来自 KubeCon 2021 北美大会的视频](https://www.youtube.com/watch?v=uZ0WLxpmBbY&list=PLj6h78yzYM2Nd1U4RMhv7v88fdiFqeYAP&index=4) +总结了 SIG 最近的更新,包括双协议栈将在 1.23 版本中稳定。 + + +当前 SIG-Network 在 GitHub 上的 [KEPs](https://github.com/orgs/kubernetes/projects/10) 和 +[issues](https://github.com/kubernetes/kubernetes/issues?q=is%3Aopen+is%3Aissue+label%3Asig%2Fnetwork) +说明了该 SIG 的重点领域。[双协议栈 API 服务器](https://github.com/kubernetes/enhancements/issues/2438) +是一个考虑贡献的方向。 + + +[SIG-Network 会议](https://github.com/kubernetes/community/tree/master/sig-network#meetings) +是一个友好、热情的场所,你可以与社区联系并分享你的想法。期待你的加入! + + +## 致谢 + + +许多 Kubernetes 贡献者为双协议栈网络做出了贡献。感谢所有贡献了代码、经验报告、文档、代码审查以及其他工作的人。 +Bridget Kromhout 在 [Kubernetes的双协议栈网络](https://containerjournal.com/features/dual-stack-networking-in-kubernetes/) +中详细介绍了这项社区工作。Tim Hockin 和 Khaled (Kal) Henidak 在 2019 年的 KubeCon 大会演讲 +([Kubernetes 通往 IPv4/IPv6 双协议栈的漫漫长路](https://www.youtube.com/watch?v=o-oMegdZcg4)) +和 Lachlan Evenson 在 2021 年演讲([我们来啦,Kubernetes 双协议栈网络](https://www.youtube.com/watch?v=o-oMegdZcg4)) +中讨论了双协议栈的发展旅程,耗时 5 年和海量代码。 From 03926364b56bbe971490cbe0927b10753f491377 Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Mon, 28 Mar 2022 13:16:53 +0800 Subject: [PATCH 071/102] [zh] Update install-kubectl-windows.md Signed-off-by: xin.li --- .../tasks/tools/install-kubectl-windows.md | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/content/zh/docs/tasks/tools/install-kubectl-windows.md b/content/zh/docs/tasks/tools/install-kubectl-windows.md index 617ca3f3ce..921a8e13a9 100644 --- a/content/zh/docs/tasks/tools/install-kubectl-windows.md +++ b/content/zh/docs/tasks/tools/install-kubectl-windows.md @@ -71,20 +71,20 @@ The following methods exist for installing kubectl on Windows: 1. 验证该可执行文件(可选步骤) - 下载 kubectl 校验和文件: + 下载 `kubectl` 校验和文件: ```powershell curl -LO "https://dl.k8s.io/{{< param "fullversion" >}}/bin/windows/amd64/kubectl.exe.sha256" ``` - 基于校验和文件,验证 kubectl 的可执行文件: + 基于校验和文件,验证 `kubectl` 的可执行文件: -1. 将 kubectl 二进制文件夹附加或添加到你的 `PATH` 环境变量中。 +1. 将 `kubectl` 二进制文件夹追加或插入到你的 `PATH` 环境变量中。 1. 测试一下,确保此 `kubectl` 的版本和期望版本一致: @@ -261,22 +261,22 @@ kubectl 为 Bash、Zsh、Fish 和 PowerShell 提供自动补全功能,可以 1. 验证该可执行文件(可选步骤) - 下载 kubectl-convert 校验和文件: + 下载 `kubectl-convert` 校验和文件: ```powershell curl -LO "https://dl.k8s.io/{{< param "fullversion" >}}/bin/windows/amd64/kubectl-convert.exe.sha256" ``` - 基于校验和,验证 kubectl-convert 的可执行文件: + 基于校验和,验证 `kubectl-convert` 的可执行文件: - 用提示的命令对 `CertUtil` 的输出和下载的校验和文件进行手动比较。 @@ -295,11 +295,11 @@ kubectl 为 Bash、Zsh、Fish 和 PowerShell 提供自动补全功能,可以 ``` -1. 将 kubectl 二进制文件夹附加或添加到你的 `PATH` 环境变量中。 +1. 将 `kubectl-convert` 二进制文件夹附加或添加到你的 `PATH` 环境变量中。 1. 验证插件是否安装成功 From b765f0fee6f2f8eeb0d8d7e9c41ac7f3bbc3938f Mon Sep 17 00:00:00 2001 From: howieyuen Date: Sat, 26 Mar 2022 14:56:22 +0800 Subject: [PATCH 072/102] [zh]translate content/docs/reference/kubernetes-api/common-definitions/quantity.md into Chinese --- .../common-definitions/quantity.md | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 content/zh/docs/reference/kubernetes-api/common-definitions/quantity.md diff --git a/content/zh/docs/reference/kubernetes-api/common-definitions/quantity.md b/content/zh/docs/reference/kubernetes-api/common-definitions/quantity.md new file mode 100644 index 0000000000..84ce0dd899 --- /dev/null +++ b/content/zh/docs/reference/kubernetes-api/common-definitions/quantity.md @@ -0,0 +1,135 @@ +--- +api_metadata: + apiVersion: "" + import: "k8s.io/apimachinery/pkg/api/resource" + kind: "Quantity" +content_type: "api_reference" +description: "数量(Quantity)是数字的定点表示。" +title: "Quantity" +weight: 10 +auto_generated: true +--- + + + + + + + +`import "k8s.io/apimachinery/pkg/api/resource"` + + + +数量(Quantity)是数字的定点表示。 +除了 String() 和 AsInt64() 的访问接口之外, +它以 JSON 和 YAML形式提供方便的打包和解包方法。 + +序列化格式如下: + + +``` + ::= + (注意 可能为空, 例如 的 "" 情形。)
+ ::= 0 | 1 | ... | 9
+ ::= |
+ ::= | . | . | .
+ ::= "+" | "-"
+ ::= |
+ ::= | |
+ ::= Ki | Mi | Gi | Ti | Pi | Ei + (国际单位制度;查阅:http://physics.nist.gov/cuu/Units/binary.html)
+ ::= m | "" | k | M | G | T | P | E + (注意,1024 = 1ki 但 1000 = 1k;我没有选择大写。)
+ ::= "e" | "E"
+``` + + + +无论使用三种指数形式中哪一种,没有数量可以表示大于 263-1 的数,也不可能超过 3 个小数位。 +更大或更精确的数字将被截断或向上取整。(例如:0.1m 将向上取整为 1m。) +如果将来我们需要更大或更小的数量,可能会扩展。 + +当从字符串解析数量时,它将记住它具有的后缀类型,并且在序列化时将再次使用相同类型。 + + +在序列化之前,数量将以“规范形式”放置。这意味着指数或者后缀将被向上或向下调整(尾数相应增加或减少),并确保: + 1. 没有精度丢失 + 2. 不会输出小数数字 + 3. 指数(或后缀)尽可能大。 +除非数量是负数,否则将省略正负号。 + + +例如: + - 1.5 将会被序列化成 “1500m” + - 1.5Gi 将会被序列化成 “1536Mi” + + +请注意,数量永远**不会**在内部以浮点数表示。这是本设计的重中之重。 + +只要它们格式正确,非规范值仍将解析,但将以其规范形式重新输出。(所以应该总是使用规范形式,否则不要执行 diff 比较。) + +这种格式旨在使得很难在不撰写某种特殊处理代码的情况下使用这些数字,进而希望实现者也使用定点实现。 + +
From 1698664aed79daf8f9bde9fbdb97c360b8f7f108 Mon Sep 17 00:00:00 2001 From: howieyuen Date: Sat, 26 Mar 2022 15:03:49 +0800 Subject: [PATCH 073/102] [zh]translate content/docs/reference/kubernetes-api/common-definitions/resource-field-selector.md into Chinese --- .../resource-field-selector.md | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 content/zh/docs/reference/kubernetes-api/common-definitions/resource-field-selector.md diff --git a/content/zh/docs/reference/kubernetes-api/common-definitions/resource-field-selector.md b/content/zh/docs/reference/kubernetes-api/common-definitions/resource-field-selector.md new file mode 100644 index 0000000000..e77543e25f --- /dev/null +++ b/content/zh/docs/reference/kubernetes-api/common-definitions/resource-field-selector.md @@ -0,0 +1,62 @@ +--- +api_metadata: + apiVersion: "" + import: "k8s.io/api/core/v1" + kind: "ResourceFieldSelector" +content_type: "api_reference" +description: "ResourceFieldSelector 表示容器资源(CPU,内存)及其输出格式。" +title: "ResourceFieldSelector" +weight: 11 +auto_generated: true +--- + + + + + + + +`import "k8s.io/api/core/v1"` + + + +ResourceFieldSelector 表示容器资源(CPU,内存)及其输出格式。 + +
+ +- **resource** (string), 必选 + + + 必选:选择的资源 + +- **containerName** (string) + + + 容器名称:对卷必选,对环境变量可选 + +- **divisor** (}}">Quantity) + + + 指定所曝光资源的输出格式,默认值为“1” + + + From a4196f77f587f210ba57dba256b591072c5d0c0b Mon Sep 17 00:00:00 2001 From: Lan Luo Date: Mon, 28 Mar 2022 21:07:51 +0800 Subject: [PATCH 074/102] Fix extra double quotation mark Signed-off-by: Lan Luo --- .../update-api-object-kubectl-patch.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/zh/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch.md b/content/zh/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch.md index a5c7cd9452..dd47ec39cf 100644 --- a/content/zh/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch.md +++ b/content/zh/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch.md @@ -613,10 +613,10 @@ The following commands are equivalent: 以下命令是等价的: ```shell -kubectl patch deployment patch-demo --patch-file patch-file.yaml" +kubectl patch deployment patch-demo --patch-file patch-file.yaml kubectl patch deployment patch-demo --patch 'spec:\n template:\n spec:\n containers:\n - name: patch-demo-ctr-2\n image: redis' -kubectl patch deployment patch-demo --patch-file patch-file.json" +kubectl patch deployment patch-demo --patch-file patch-file.json kubectl patch deployment patch-demo --patch '{"spec": {"template": {"spec": {"containers": [{"name": "patch-demo-ctr-2","image": "redis"}]}}}}' ``` From d21c4302bc793971697f6ce6ddd1fa05ceac00c1 Mon Sep 17 00:00:00 2001 From: Mitesh Jain <47820816+miteshskj@users.noreply.github.com> Date: Mon, 28 Mar 2022 19:17:39 +0530 Subject: [PATCH 075/102] Remove bootstrap token being in beta state in kubelet-tls-bootstrapping.md --- .../command-line-tools-reference/kubelet-tls-bootstrapping.md | 1 - 1 file changed, 1 deletion(-) diff --git a/content/en/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping.md b/content/en/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping.md index 5d2458079e..78aee8cf06 100644 --- a/content/en/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping.md +++ b/content/en/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping.md @@ -126,7 +126,6 @@ of provisioning. 2. [Token authentication file](#token-authentication-file) Bootstrap tokens are a simpler and more easily managed method to authenticate kubelets, and do not require any additional flags when starting kube-apiserver. -Using bootstrap tokens is currently __beta__ as of Kubernetes version 1.12. Whichever method you choose, the requirement is that the kubelet be able to authenticate as a user with the rights to: From 5183202a3bf782ed4cbecf0b3999ee454c3ad1a4 Mon Sep 17 00:00:00 2001 From: Bob <39816893+bobcode99@users.noreply.github.com> Date: Mon, 28 Mar 2022 22:36:36 +0800 Subject: [PATCH 076/102] Update horizontal-pod-autoscale.md Update HPA V2, custom.metrics.k8s.io, external.metrics.k8s.io design proposals to archive github link. --- .../docs/tasks/run-application/horizontal-pod-autoscale.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/en/docs/tasks/run-application/horizontal-pod-autoscale.md b/content/en/docs/tasks/run-application/horizontal-pod-autoscale.md index e5c05ea90c..0039254f7e 100644 --- a/content/en/docs/tasks/run-application/horizontal-pod-autoscale.md +++ b/content/en/docs/tasks/run-application/horizontal-pod-autoscale.md @@ -337,9 +337,9 @@ APIs, cluster administrators must ensure that: * For external metrics, this is the `external.metrics.k8s.io` API. It may be provided by the custom metrics adapters provided above. For more information on these different metrics paths and how they differ please see the relevant design proposals for -[the HPA V2](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/autoscaling/hpa-v2.md), -[custom.metrics.k8s.io](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/instrumentation/custom-metrics-api.md) -and [external.metrics.k8s.io](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/instrumentation/external-metrics-api.md). +[the HPA V2](https://github.com/kubernetes/design-proposals-archive/blob/main/autoscaling/hpa-v2.md), +[custom.metrics.k8s.io](https://github.com/kubernetes/design-proposals-archive/blob/main/instrumentation/custom-metrics-api.md) +and [external.metrics.k8s.io](https://github.com/kubernetes/design-proposals-archive/blob/main/instrumentation/external-metrics-api.md). For examples of how to use them see [the walkthrough for using custom metrics](/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#autoscaling-on-multiple-metrics-and-custom-metrics) and [the walkthrough for using external metrics](/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#autoscaling-on-metrics-not-related-to-kubernetes-objects). From a76cc64203cecbdb804944664311fa6d86537be6 Mon Sep 17 00:00:00 2001 From: Mitesh Jain <47820816+miteshskj@users.noreply.github.com> Date: Mon, 28 Mar 2022 20:53:39 +0530 Subject: [PATCH 077/102] Fix broken link for stale CSR clean up in garbage-collection.md --- content/en/docs/concepts/architecture/garbage-collection.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/concepts/architecture/garbage-collection.md b/content/en/docs/concepts/architecture/garbage-collection.md index 38aa99d654..a6fa885bfc 100644 --- a/content/en/docs/concepts/architecture/garbage-collection.md +++ b/content/en/docs/concepts/architecture/garbage-collection.md @@ -13,7 +13,7 @@ allows the clean up of resources like the following: * [Objects without owner references](#owners-dependents) * [Unused containers and container images](#containers-images) * [Dynamically provisioned PersistentVolumes with a StorageClass reclaim policy of Delete](/docs/concepts/storage/persistent-volumes/#delete) - * [Stale or expired CertificateSigningRequests (CSRs)](/reference/access-authn-authz/certificate-signing-requests/#request-signing-process) + * [Stale or expired CertificateSigningRequests (CSRs)](/docs/reference/access-authn-authz/certificate-signing-requests/#request-signing-process) * {{}} deleted in the following scenarios: * On a cloud when the cluster uses a [cloud controller manager](/docs/concepts/architecture/cloud-controller/) * On-premises when the cluster uses an addon similar to a cloud controller From abab541c57768f977535c6979d7ca82d56076c6e Mon Sep 17 00:00:00 2001 From: Ilya Z Date: Mon, 28 Mar 2022 23:40:05 +0400 Subject: [PATCH 078/102] small_fix --- content/ru/docs/reference/kubectl/overview.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/content/ru/docs/reference/kubectl/overview.md b/content/ru/docs/reference/kubectl/overview.md index 58305f2d95..15a0a3e611 100644 --- a/content/ru/docs/reference/kubectl/overview.md +++ b/content/ru/docs/reference/kubectl/overview.md @@ -52,7 +52,7 @@ kubectl [command] [TYPE] [NAME] [flags] * Выбор ресурсов по одному или нескольким файлов: `-f file1 -f file2 -f file<#>` - * [Используйте YAML вместо JSON](/docs/concepts/configuration/overview/#general-configuration-tips), так так YAML удобнее для пользователей, особенно в конфигурационных файлов.
+ * [Используйте YAML вместо JSON](/docs/concepts/configuration/overview/#general-configuration-tips), так как YAML удобнее для пользователей, особенно в конфигурационных файлах.
Пример: `kubectl get pod -f ./pod.yaml` * `flags`: определяет дополнительные флаги. Например, вы можете использовать флаги `-s` или `--server`, чтобы указать адрес и порт API-сервера Kubernetes.
@@ -162,7 +162,7 @@ kubectl [command] [TYPE] [NAME] [flags] ### Форматирование вывода -Стандартный формат вывода всех команд `kubectl` представлен в человекочитаемом текстовом формате. Чтобы вывести подробности в определенном формате можно добавить флаги `-o` или `--output` к команде `kubectl`. +Стандартный формат вывода всех команд `kubectl` представлен в понятном для человека текстовом формате. Чтобы вывести подробности в определенном формате можно добавить флаги `-o` или `--output` к команде `kubectl`. #### Синтаксис @@ -229,7 +229,7 @@ submit-queue 610995 `kubectl` может получать информацию об объектах с сервера. Это означает, что для любого указанного ресурса сервер вернет столбцы и строки по этому ресурсу, которые отобразит клиент. -Благодаря тому, что сервер инкапсулирует реализацию вывода, гарантируется единообразный и человекочитаемый вывод на всех клиентах, использующих один и тот же кластер. +Благодаря тому, что сервер инкапсулирует реализацию вывода, гарантируется единообразный и понятный для человека вывод на всех клиентах, использующих один и тот же кластер. Эта функциональность включена по умолчанию, начиная с `kubectl` 1.11 и выше. Чтобы отключить ее, добавьте флаг `--server-print=false` в команду `kubectl get`. @@ -340,7 +340,7 @@ kubectl delete pods,services -l name= kubectl delete pods --all ``` -`kubectl exec` - Выполнить команду в контейнера пода. +`kubectl exec` - Выполнить команду в контейнере пода. ```shell # Получить вывод от запущенной команды 'date' в поде . По умолчанию отображается вывод из первого контейнера. From 5ff402c477f792e4bd14658dfee4a5e78647dd6b Mon Sep 17 00:00:00 2001 From: Tim Bannister Date: Mon, 28 Mar 2022 23:08:25 +0100 Subject: [PATCH 079/102] Remove incorrect /dockershim alias This fixes up a previous, inadvertent mistake where the alias was retained during localization. --- content/pt-br/blog/_posts/2022-02-17-updated-dockershim-faq.md | 1 - 1 file changed, 1 deletion(-) diff --git a/content/pt-br/blog/_posts/2022-02-17-updated-dockershim-faq.md b/content/pt-br/blog/_posts/2022-02-17-updated-dockershim-faq.md index 526ec6e344..bf92c1fedc 100644 --- a/content/pt-br/blog/_posts/2022-02-17-updated-dockershim-faq.md +++ b/content/pt-br/blog/_posts/2022-02-17-updated-dockershim-faq.md @@ -3,7 +3,6 @@ layout: blog title: "Atualizado: Perguntas frequentes (FAQ) sobre a remoção do Dockershim" date: 2022-02-17 slug: dockershim-faq -aliases: [ '/dockershim' ] --- **Esta é uma atualização do artigo original [FAQ sobre a depreciação do Dockershim](/blog/2020/12/02/dockershim-faq/), From fb3db4db2b84f9df11a9a87c551ba9e6a5370d05 Mon Sep 17 00:00:00 2001 From: Tim Bannister Date: Mon, 28 Mar 2022 23:46:34 +0100 Subject: [PATCH 080/102] Remove incorrect /dockershim alias This fixes up a previous, inadvertent mistake where the alias was retained during localization. --- content/zh/blog/_posts/2022-02-17-updated-dockershim-faq.md | 1 - 1 file changed, 1 deletion(-) diff --git a/content/zh/blog/_posts/2022-02-17-updated-dockershim-faq.md b/content/zh/blog/_posts/2022-02-17-updated-dockershim-faq.md index 9a1cac8cc2..8400012b61 100644 --- a/content/zh/blog/_posts/2022-02-17-updated-dockershim-faq.md +++ b/content/zh/blog/_posts/2022-02-17-updated-dockershim-faq.md @@ -3,7 +3,6 @@ layout: blog title: "更新:弃用 Dockershim 的常见问题" date: 2022-02-17 slug: dockershim-faq -aliases: [ '/dockershim' ] --- @@ -38,8 +39,8 @@ Secret 是一种包含少量敏感信息例如密码、令牌或密钥的对象 Because Secrets can be created independently of the Pods that use them, there is less risk of the Secret (and its data) being exposed during the workflow of creating, viewing, and editing Pods. Kubernetes, and applications that run in -your cluster, can also take additional precautions with Secrets, such as -avoiding writing confidential data to nonvolatile storage. +your cluster, can also take additional precautions with Secrets, such as avoiding +writing confidential data to nonvolatile storage. Secrets are similar to {{< glossary_tooltip text="ConfigMaps" term_id="configmap" >}} but are specifically intended to hold confidential data. @@ -60,9 +61,11 @@ Additionally, anyone who is authorized to create a Pod in a namespace can use th In order to safely use Secrets, take at least the following steps: 1. [Enable Encryption at Rest](/docs/tasks/administer-cluster/encrypt-data/) for Secrets. -2. Enable or configure [RBAC rules](/docs/reference/access-authn-authz/authorization/) that - restrict reading data in Secrets (including via indirect means). -3. Where appropriate, also use mechanisms such as RBAC to limit which principals are allowed to create new Secrets or replace existing ones. +1. Enable or configure [RBAC rules](/docs/reference/access-authn-authz/authorization/) that + restrict reading and writing data in Secrets. Be aware that secrets can be obtained + implicitly by anyone with the permission to create a Pod. +1. Where appropriate, also use mechanisms such as RBAC to limit which principals are allowed + to create new Secrets or replace existing ones. --> 默认情况下,Kubernetes Secret 未加密地存储在 API 服务器的底层数据存储(etcd)中。 任何拥有 API 访问权限的人都可以检索或修改 Secret,任何有权访问 etcd 的人也可以。 @@ -72,65 +75,1271 @@ In order to safely use Secrets, take at least the following steps: 为了安全地使用 Secret,请至少执行以下步骤: 1. 为 Secret [启用静态加密](/zh/docs/tasks/administer-cluster/encrypt-data/); -2. 启用或配置 [RBAC 规则](/zh/docs/reference/access-authn-authz/authorization/)来限制读取 Secret 的数据(包括通过间接方式)。 -3. 在适当的情况下,还可以使用 RBAC 等机制来限制允许哪些主体创建新 Secret 或替换现有 Secret。 +1. 启用或配置 [RBAC 规则](/zh/docs/reference/access-authn-authz/authorization/)来限制读取和写入 + Secret 的数据(包括通过间接方式)。需要注意的是,被准许创建 Pod 的人也隐式地被授权获取 + Secret 内容。 +1. 在适当的情况下,还可以使用 RBAC 等机制来限制允许哪些主体创建新 Secret 或替换现有 Secret。 {{< /caution >}} + +参见 [Secret 的信息安全](#information-security-for-secrets)了解详情。 + -## Secret 概览 {#overview-of-secrets} -要使用 Secret,Pod 需要引用 Secret。 -Pod 可以用三种方式之一来使用 Secret: - -- 作为挂载到一个或多个容器上的 {{< glossary_tooltip text="卷" term_id="volume" >}} - 中的[文件](#using-secrets-as-files-from-a-pod)。 -- 作为[容器的环境变量](#using-secrets-as-environment-variables) -- 由 [kubelet 在为 Pod 拉取镜像时使用](#using-imagepullsecrets) - - -Kubernetes 控制平面也使用 Secret; +## Secret 的使用 {#uses-for-secrets} + +Pod 可以用三种方式之一来使用 Secret: + +- 作为挂载到一个或多个容器上的{{< glossary_tooltip text="卷" term_id="volume" >}} + 中的[文件](#using-secrets-as-files-from-a-pod)。 +- 作为[容器的环境变量](#using-secrets-as-environment-variables)。 +- 由 [kubelet 在为 Pod 拉取镜像时使用](#using-imagepullsecrets)。 + +Kubernetes 控制面也使用 Secret; 例如,[引导令牌 Secret](#bootstrap-token-secrets) 是一种帮助自动化节点注册的机制。 +### Secret 的替代方案 {#alternatives-to-secrets} + +除了使用 Secret 来保护机密数据,你也可以选择一些替代方案。 + +下面是一些选项: + + +- 如果你的云原生组件需要执行身份认证来访问你所知道的、在同一 Kubernetes 集群中运行的另一个应用, + 你可以使用 [ServiceAccount](/zh/docs/reference/access-authn-authz/authentication/#service-account-tokens) + 及其令牌来标识你的客户端身份。 +- 你可以运行的第三方工具也有很多,这些工具可以运行在集群内或集群外,提供机密数据管理。 + 例如,这一工具可能是 Pod 通过 HTTPS 访问的一个服务,该服务在客户端能够正确地通过身份认证 + (例如,通过 ServiceAccount 令牌)时,提供机密数据内容。 + +- 就身份认证而言,你可以为 X.509 证书实现一个定制的签名者,并使用 + [CertificateSigningRequest](/zh/docs/reference/access-authn-authz/certificate-signing-requests/) + 来让该签名者为需要证书的 Pod 发放证书。 +- 你可以使用一个[设备插件](/zh/docs/concepts/extend-kubernetes/compute-storage-net/device-plugins/) + 来将节点本地的加密硬件暴露给特定的 Pod。例如,你可以将可信任的 Pod + 调度到提供可信平台模块(Trusted Platform Module,TPM)的节点上。 + 这类节点是另行配置的。 + + +你还可以将如上选项的两种或多种进行组合,包括直接使用 Secret 对象本身也是一种选项。 + +例如:实现(或部署)一个 {{< glossary_tooltip text="operator" term_id="operator-pattern" >}}, +从外部服务取回生命期很短的会话令牌,之后基于这些生命期很短的会话令牌来创建 Secret。 +运行在集群中的 Pod 可以使用这些会话令牌,而 Operator 则确保这些令牌是合法的。 +这种责权分离意味着你可以运行那些不了解会话令牌如何发放与刷新的确切机制的 Pod。 + + +## 使用 Secret {#working-with-secrets} + +### 创建 Secret {#creating-a-secret} + +- [使用 `kubectl` 命令来创建 Secret](/zh/docs/tasks/configmap-secret/managing-secret-using-kubectl/) +- [基于配置文件来创建 Secret](/zh/docs/tasks/configmap-secret/managing-secret-using-config-file/) +- [使用 kustomize 来创建 Secret](/zh/docs/tasks/configmap-secret/managing-secret-using-kustomize/) + + +#### 对 Secret 名称与数据的约束 {#restriction-names-data} + +Secret 对象的名称必须是合法的 +[DNS 子域名](/zh/docs/concepts/overview/working-with-objects/names#dns-subdomain-names)。 + + -Secret 对象的名称必须是合法的 [DNS 子域名](/zh/docs/concepts/overview/working-with-objects/names#dns-subdomain-names)。 在为创建 Secret 编写配置文件时,你可以设置 `data` 与/或 `stringData` 字段。 `data` 和 `stringData` 字段都是可选的。`data` 字段中所有键值都必须是 base64 编码的字符串。如果不希望执行这种 base64 字符串的转换操作,你可以选择设置 `stringData` 字段,其中可以使用任何字符串作为其取值。 +`data` 和 `stringData` 中的键名只能包含字母、数字、`-`、`_` 或 `.` 字符。 +`stringData` 字段中的所有键值对都会在内部被合并到 `data` 字段中。 +如果某个主键同时出现在 `data` 和 `stringData` 字段中,`stringData` +所指定的键值具有高优先级。 + + +#### 尺寸限制 {#restriction-data-size} + +每个 Secret 的尺寸最多为 1MiB。施加这一限制是为了避免用户创建非常大的 Secret, +进而导致 API 服务器和 kubelet 内存耗尽。不过创建很多小的 Secret 也可能耗尽内存。 +你可以使用[资源配额](/zh/docs/concepts/policy/resource-quotas/)来约束每个名字空间中 +Secret(或其他资源)的个数。 + + +### 编辑 Secret {#editing-a-secret} + +你可以使用 kubectl 来编辑一个已有的 Secret: + +```shell +kubectl edit secrets mysecret +``` + +这一命令会启动你的默认编辑器,允许你更新 `data` 字段中存放的 base64 编码的 Secret 值; +例如: + +```yaml +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file, it will be +# reopened with the relevant failures. +# +apiVersion: v1 +data: + username: YWRtaW4= + password: MWYyZDFlMmU2N2Rm +kind: Secret +metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: { ... } + creationTimestamp: 2020-01-22T18:41:56Z + name: mysecret + namespace: default + resourceVersion: "164619" + uid: cfee02d6-c137-11e5-8d73-42010af00002 +type: Opaque +``` + + +这一示例清单定义了一个 Secret,其 `data` 字段中包含两个主键:`username` 和 `password`。 +清单中的字段值是 Base64 字符串,不过,当你在 Pod 中使用 Secret 时,kubelet 为 Pod +及其中的容器提供的是解码后的数据。 + +你可以在一个 Secret 中打包多个主键和数值,也可以选择使用多个 Secret, +完全取决于哪种方式最方便。 + + +### 使用 Secret {#using-a-secret} + +Secret 可以以数据卷的形式挂载,也可以作为{{< glossary_tooltip text="环境变量" term_id="container-env-variables" >}} +暴露给 Pod 中的容器使用。Secret 也可用于系统中的其他部分,而不是一定要直接暴露给 Pod。 +例如,Secret 也可以包含系统中其他部分在替你与外部系统交互时要使用的凭证数据。 + + +Kubernetes 会检查 Secret 的卷数据源,确保所指定的对象引用确实指向类型为 Secret +的对象。因此,如果 Pod 依赖于某 Secret,该 Secret 必须先于 Pod 被创建。 + +如果 Secret 内容无法取回(可能因为 Secret 尚不存在或者临时性地出现 API +服务器网络连接问题),kubelet 会周期性地重试 Pod 运行操作。kubelet 也会为该 Pod +报告 Event 事件,给出读取 Secret 时遇到的问题细节。 + + +#### 可选的 Secret {#restriction-secret-must-exist} + +当你定义一个基于 Secret 的环境变量时,你可以将其标记为可选。 +默认情况下,所引用的 Secret 都是必需的。 + +只有所有非可选的 Secret 都可用时,Pod 中的容器才能启动运行。 + +如果 Pod 引用了 Secret 中的特定主键,而虽然 Secret 本身存在,对应的主键不存在, +Pod 启动也会失败。 + + +### 在 Pod 中以文件形式使用 Secret {#using-secrets-as-files-from-a-pod} + +如果你希望在 Pod 中访问 Secret 内的数据,一种方式是让 Kubernetes 将 Secret +以 Pod 中一个或多个容器的文件系统中的文件的形式呈现出来。 + +要配置这种行为,你需要: + + +1. 创建一个 Secret 或者使用已有的 Secret。多个 Pod 可以引用同一个 Secret。 +1. 更改 Pod 定义,在 `.spec.volumes[]` 下添加一个卷。根据需要为卷设置其名称, + 并将 `.spec.volumes[].secret.secretName` 字段设置为 Secret 对象的名称。 +1. 为每个需要该 Secret 的容器添加 `.spec.containers[].volumeMounts[]`。 + 并将 `.spec.containers[].volumeMounts[].readyOnly` 设置为 `true`, + 将 `.spec.containers[].volumeMounts[].mountPath` 设置为希望 Secret + 被放置的、目前尚未被使用的路径名。 +1. 更改你的镜像或命令行,以便程序读取所设置的目录下的文件。Secret 的 `data` + 映射中的每个主键都成为 `mountPath` 下面的文件名。 + +下面是一个通过卷来挂载名为 `mysecret` 的 Secret 的 Pod 示例: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: mypod +spec: + containers: + - name: mypod + image: redis + volumeMounts: + - name: foo + mountPath: "/etc/foo" + readOnly: true + volumes: + - name: foo + secret: + secretName: mysecret + optional: false # 默认设置,意味着 "mysecret" 必须已经存在 +``` + + +你要访问的每个 Secret 都需要通过 `.spec.volumes` 来引用。 + +如果 Pod 中包含多个容器,则每个容器需要自己的 `volumeMounts` 块, +不过针对每个 Secret 而言,只需要一份 `.spec.volumes` 设置。 + +{{< note >}} + +Kubernetes v1.22 版本之前都会自动创建用来访问 Kubernetes API 的凭证。 +这一老的机制是基于创建可被挂载到 Pod 中的令牌 Secret 来实现的。 +在最近的版本中,包括 Kubernetes v{{< skew currentVersion >}} 中,API 凭据是直接通过 +[TokenRequest](/docs/reference/kubernetes-api/authentication-resources/token-request-v1/) +API 来获得的,这一凭据会使用[投射卷](/zh/docs/reference/access-authn-authz/service-accounts-admin/#bound-service-account-token-volume) +挂载到 Pod 中。使用这种方式获得的令牌有确定的生命期,并且在挂载它们的 Pod +被删除时自动作废。 + + +你仍然可以[手动创建](/zh/docs/tasks/configure-pod-container/configure-service-account/#manually-create-a-service-account-api-token) +服务账号令牌。例如,当你需要一个永远都不过期的令牌时。 +不过,仍然建议使用 [TokenRequest](/docs/reference/kubernetes-api/authentication-resources/token-request-v1/) +子资源来获得访问 API 服务器的令牌。 +{{< /note >}} + + +#### 将 Secret 键投射到特定目录 + +你也可以控制 Secret 键所投射到的卷中的路径。 +你可以使用 `.spec.volumes[].secret.items` 字段来更改每个主键的目标路径: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: mypod +spec: + containers: + - name: mypod + image: redis + volumeMounts: + - name: foo + mountPath: "/etc/foo" + readOnly: true + volumes: + - name: foo + secret: + secretName: mysecret + items: + - key: username + path: my-group/my-username +``` + + +将发生的事情如下: + +- `mysecret` 中的键 `username` 会出现在容器中的路径为 `/etc/foo/my-group/my-username`, + 而不是 `/etc/foo/username`。 +- Secret 对象的 `password` 键不会被投射。 + +如果使用了 `.spec.volumes[].secret.items`,则只有 `items` 中指定了的主键会被投射。 +如果要使用 Secret 中的所有主键,则需要将它们全部枚举到 `items` 字段中。 + +如果你显式地列举了主键,则所列举的主键都必须在对应的 Secret 中存在。 +否则所在的卷不会被创建。 + + +#### Secret 文件的访问权限 + +你可以为某个 Secret 主键设置 POSIX 文件访问权限位。 +如果你不指定访问权限,默认会使用 `0644`。 +你也可以为整个 Secret 卷设置默认的访问模式,然后再根据需要在主键层面重载。 + +例如,你可以像下面这样设置默认的模式: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: mypod +spec: + containers: + - name: mypod + image: redis + volumeMounts: + - name: foo + mountPath: "/etc/foo" + volumes: + - name: foo + secret: + secretName: mysecret + defaultMode: 0400 +``` + + +该 Secret 被挂载在 `/etc/foo` 下,Secret 卷挂载所创建的所有文件的访问模式都是 `0400`。 + +{{< note >}} + +如果你是使用 JSON 来定义 Pod 或 Pod 模板,需要注意 JSON 规范不支持八进制的记数方式。 +你可以在 `defaultMode` 中设置十进制的值(例如,八进制中的 0400 在十进制中为 256)。 +如果你使用 YAML 来编写定义,你可以用八进制值来设置 `defaultMode`。 +{{< /note >}} + + +#### 使用来自卷中的 Secret 值 {#consuming-secret-values-from-volumes} + +在挂载了 Secret 卷的容器内,Secret 的主键都呈现为文件。 +Secret 的取值都是 Base64 编码的,保存在这些文件中。 + +下面是在上例中的容器内执行命令的结果: + +```shell +ls /etc/foo/ +``` + + +输出类似于: + +``` +username +password +``` + +```shell +cat /etc/foo/username +``` + + +输出类似于: + +``` +admin +``` + +```shell +cat /etc/foo/password +``` + + +输出类似于: + +``` +1f2d1e2e67df +``` + + +容器中的程序要负责根据需要读取 Secret 数据。 + + +#### 挂载的 Secret 是被自动更新的 {#mounted-secrets-are-updated-automatically} + +当卷中包含来自 Secret 的数据,而对应的 Secret 被更新,Kubernetes +会跟踪到这一操作并更新卷中的数据。更新的方式是保证最终一致性。 + +{{< note >}} + +对于以 [subPath](/zh/docs/concepts/storage/volumes#using-subpath) 形式挂载 Secret 卷的容器而言, +它们无法收到自动的 Secret 更新。 +{{< /note >}} + + +Kubelet 组件会维护一个缓存,在其中保存节点上 Pod 卷中使用的 Secret 的当前主键和取值。 +你可以配置 kubelet 如何检测所缓存数值的变化。 +[kubelet 配置](/zh/docs/reference/config-api/kubelet-config.v1beta1/)中的 +`configMapAndSecretChangeDetectionStrategy` 字段控制 kubelet 所采用的策略。 +默认的策略是 `Watch`。 + + +对 Secret 的更新操作既可以通过 API 的 watch 机制(默认)来传播, +基于设置了生命期的缓存获取,也可以通过 kubelet 的同步回路来从集群的 API +服务器上轮询获取。 + + +因此,从 Secret 被更新到新的主键被投射到 Pod 中,中间存在一个延迟。 +这一延迟的上限是 kubelet 的同步周期加上缓存的传播延迟, +其中缓存的传播延迟取决于所选择的缓存类型。 +对应上一段中提到的几种传播机制,延迟时长为 watch 的传播延迟、所配置的缓存 TTL +或者对于直接轮询而言是零。 + + +### 以环境变量的方式使用 Secret {#using-secrets-as-environment-variables} + +如果需要在 Pod 中以{{< glossary_tooltip text="环境变量" term_id="container-env-variables" >}} +的形式使用 Secret: + + +1. 创建 Secret(或者使用现有 Secret)。多个 Pod 可以引用同一个 Secret。 +1. 更改 Pod 定义,在要使用 Secret 键值的每个容器中添加与所使用的主键对应的环境变量。 + 读取 Secret 主键的环境变量应该在 `env[].valueFrom.secretKeyRef` 中填写 Secret + 的名称和主键名称。 +1. 更改你的镜像或命令行,以便程序读取环境变量中保存的值。 + + +下面是一个通过环境变量来使用 Secret 的示例 Pod: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: secret-env-pod +spec: + containers: + - name: mycontainer + image: redis + env: + - name: SECRET_USERNAME + valueFrom: + secretKeyRef: + name: mysecret + key: username + optional: false # 此值为默认值;意味着 "mysecret" + # 必须存在且包含名为 "username" 的主键 + - name: SECRET_PASSWORD + valueFrom: + secretKeyRef: + name: mysecret + key: password + optional: false # 此值为默认值;意味着 "mysecret" + # 必须存在且包含名为 "password" 的主键 + restartPolicy: Never +``` + + +#### 非法环境变量 {#restriction-env-from-invalid} + +对于通过 `envFrom` 字段来填充环境变量的 Secret 而言, +如果其中包含的主键不能被当做合法的环境变量名,这些主键会被忽略掉。 +Pod 仍然可以启动。 + + +如果你定义的 Pod 中包含非法的变量名称,则 Pod 可能启动失败, +会形成 reason 为 `InvalidVariableNames` 的事件,以及列举被略过的非法主键的消息。 +下面的例子中展示了一个 Pod,引用的是名为 `mysecret` 的 Secret, +其中包含两个非法的主键:`1badkey` 和 `2alsobad`。 + +```shell +kubectl get events +``` + + +输出类似于: + +``` +LASTSEEN FIRSTSEEN COUNT NAME KIND SUBOBJECT TYPE REASON +0s 0s 1 dapi-test-pod Pod Warning InvalidEnvironmentVariableNames kubelet, 127.0.0.1 Keys [1badkey, 2alsobad] from the EnvFrom secret default/mysecret were skipped since they are considered invalid environment variable names. +``` + + +#### 通过环境变量使用 Secret 值 + +在通过环境变量来使用 Secret 的容器中,Secret 主键展现为普通的环境变量。 +这些变量的取值是 Secret 数据的 Base64 解码值。 + +下面是在前文示例中的容器内执行命令的结果: + +```shell +echo "$SECRET_USERNAME" +``` + + +输出类似于: + +``` +admin +``` + +```shell +echo "$SECRET_PASSWORD" +``` + + +输出类似于: + +``` +1f2d1e2e67df +``` + +{{< note >}} + +如果容器已经在通过环境变量来使用 Secret,Secret 更新在容器内是看不到的, +除非容器被重启。有一些第三方的解决方案,能够在 Secret 发生变化时触发容器重启。 +{{< /note >}} + + +### 容器镜像拉取 Secret {#using-imagepullsecrets} + +如果你尝试从私有仓库拉取容器镜像,你需要一种方式让每个节点上的 kubelet +能够完成与镜像库的身份认证。你可以配置 *镜像拉取 Secret* 来实现这点。 +Secret 是在 Pod 层面来配置的。 + + +Pod 的 `imagePullSecrets` 字段是一个对 Pod 所在的名字空间中的 Secret +的引用列表。你可以使用 `imagePullSecrets` 来将镜像仓库访问凭据传递给 kubelet。 +kubelet 使用这个信息来替你的 Pod 拉取私有镜像。 +参阅 [Pod API 参考](/docs/reference/kubernetes-api/workload-resources/pod-v1/#PodSpec) +中的 `PodSpec` 进一步了解 `imagePullSecrets` 字段。 + + +#### 使用 imagePullSecrets + +`imagePullSecrets` 字段是一个列表,包含对同一名字空间中 Secret 的引用。 +你可以使用 `imagePullSecrets` 将包含 Docker(或其他)镜像仓库密码的 Secret +传递给 kubelet。kubelet 使用此信息来替 Pod 拉取私有镜像。 +参阅 [PodSpec API ](/docs/reference/kubernetes-api/workload-resources/pod-v1/#PodSpec) +进一步了解 `imagePullSecrets` 字段。 + + +##### 手动设定 imagePullSecret + +你可以通过阅读[容器镜像](/zh/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod) +文档了解如何设置 `imagePullSecrets`。 + + +##### 设置 imagePullSecrets 为自动挂载 + +你可以手动创建 `imagePullSecret`,并在一个 ServiceAccount 中引用它。 +对使用该 ServiceAccount 创建的所有 Pod,或者默认使用该 ServiceAccount 创建的 Pod +而言,其 `imagePullSecrets` 字段都会设置为该服务账号。 +请阅读[向服务账号添加 ImagePullSecrets](/zh/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account) +来详细了解这一过程。 + + +### 在静态 Pod 中使用 Secret {#restriction-static-pod} + +你不可以在{{< glossary_tooltip text="静态 Pod" term_id="static-pod" >}}. +中使用 ConfigMap 或 Secret。 + + +## 使用场景 {#use-case} + +### 使用场景:作为容器环境变量 + +创建 Secret: + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: mysecret +type: Opaque +data: + USER_NAME: YWRtaW4= + PASSWORD: MWYyZDFlMmU2N2Rm +``` + + +创建 Secret: + +```shell +kubectl apply -f mysecret.yaml +``` + + +使用 `envFrom` 来将 Secret 的所有数据定义为容器的环境变量。 +来自 Secret 的主键成为 Pod 中的环境变量名称: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: secret-test-pod +spec: + containers: + - name: test-container + image: k8s.gcr.io/busybox + command: [ "/bin/sh", "-c", "env" ] + envFrom: + - secretRef: + name: mysecret + restartPolicy: Never +``` + + +### 使用场景:带 SSH 密钥的 Pod + +创建包含一些 SSH 密钥的 Secret: + +```shell +kubectl create secret generic ssh-key-secret --from-file=ssh-privatekey=/path/to/.ssh/id_rsa --from-file=ssh-publickey=/path/to/.ssh/id_rsa.pub +``` + + +输出类似于: + +``` +secret "ssh-key-secret" created +``` + + +你也可以创建一个 `kustomization.yaml` 文件,在其 `secretGenerator` +字段中包含 SSH 密钥。 + +{{< caution >}} + +在提供你自己的 SSH 密钥之前要仔细思考:集群的其他用户可能有权访问该 Secret。 + + +你也可以创建一个 SSH 私钥,代表一个你希望与你共享 Kubernetes 集群的其他用户分享的服务标识。 +当凭据信息被泄露时,你可以收回该访问权限。 +{{< /caution >}} + + +现在你可以创建一个 Pod,在其中访问包含 SSH 密钥的 Secret,并通过卷的方式来使用它: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: secret-test-pod + labels: + name: secret-test +spec: + volumes: + - name: secret-volume + secret: + secretName: ssh-key-secret + containers: + - name: ssh-test-container + image: mySshImage + volumeMounts: + - name: secret-volume + readOnly: true + mountPath: "/etc/secret-volume" +``` + + +容器命令执行时,秘钥的数据可以在下面的位置访问到: + +``` +/etc/secret-volume/ssh-publickey +/etc/secret-volume/ssh-privatekey +``` + + +容器就可以随便使用 Secret 数据来建立 SSH 连接。 + + +### 使用场景:带有生产、测试环境凭据的 Pod + +这一示例所展示的一个 Pod 会使用包含生产环境凭据的 Secret,另一个 Pod +使用包含测试环境凭据的 Secret。 + +你可以创建一个带有 `secretGenerator` 字段的 `kustomization.yaml` 文件或者运行 +`kubectl create secret` 来创建 Secret。 + +```shell +kubectl create secret generic prod-db-secret --from-literal=username=produser --from-literal=password=Y4nys7f11 +``` + + +输出类似于: + +``` +secret "prod-db-secret" created +``` + + +你也可以创建一个包含测试环境凭据的 Secret: + +```shell +kubectl create secret generic test-db-secret --from-literal=username=testuser --from-literal=password=iluvtests +``` + + +输出类似于: + +``` +secret "test-db-secret" created +``` + +{{< note >}} + +特殊字符(例如 `$`、`\`、`*`、`=` 和 `!`)会被你的 +[Shell](https://en.wikipedia.org/wiki/Shell_(computing))解释,因此需要转义。 + + +在大多数 Shell 中,对密码进行转义的最简单方式是用单引号(`'`)将其括起来。 +例如,如果你的实际密码是 `S!B\*d$zDsb`,则应通过以下方式执行命令: + +```shell +kubectl create secret generic dev-db-secret --from-literal=username=devuser --from-literal=password='S!B\*d$zDsb=' +``` + +你无需对文件中的密码(`--from-file`)中的特殊字符进行转义。 +{{< /note >}} + + +现在生成 Pod: + +```shell +cat < pod.yaml +apiVersion: v1 +kind: List +items: +- kind: Pod + apiVersion: v1 + metadata: + name: prod-db-client-pod + labels: + name: prod-db-client + spec: + volumes: + - name: secret-volume + secret: + secretName: prod-db-secret + containers: + - name: db-client-container + image: myClientImage + volumeMounts: + - name: secret-volume + readOnly: true + mountPath: "/etc/secret-volume" +- kind: Pod + apiVersion: v1 + metadata: + name: test-db-client-pod + labels: + name: test-db-client + spec: + volumes: + - name: secret-volume + secret: + secretName: test-db-secret + containers: + - name: db-client-container + image: myClientImage + volumeMounts: + - name: secret-volume + readOnly: true + mountPath: "/etc/secret-volume" +EOF +``` + + +将 Pod 添加到同一 `kustomization.yaml` 文件中: + +```shell +cat <> kustomization.yaml +resources: +- pod.yaml +EOF +``` + + +通过下面的命令在 API 服务器上应用所有这些对象: + +```shell +kubectl apply -k . +``` + + +两个文件都会在其文件系统中出现下面面的文件,文件中内容是各个容器的环境值: + +``` +/etc/secret-volume/username +/etc/secret-volume/password +``` + + +注意这两个 Pod 的规约中只有一个字段不同。 +这便于基于相同的 Pod 模板生成具有不同能力的 Pod。 + + +你可以通过使用两个服务账号来进一步简化这一基本的 Pod 规约: + +1. `prod-user` 服务账号使用 `prod-db-secret` +1. `test-user` 服务账号使用 `test-db-secret` + +Pod 规约简化为: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: prod-db-client-pod + labels: + name: prod-db-client +spec: + serviceAccount: prod-db-client + containers: + - name: db-client-container + image: myClientImage +``` + + +### 使用场景:在 Secret 卷中带句点的文件 + +通过定义以句点(`.`)开头的主键,你可以“隐藏”你的数据。 +这些主键代表的是以句点开头的文件或“隐藏”文件。 +例如,当下面的 Secret 被挂载到 `secret-volume` 卷中时: + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: dotfile-secret +data: + .secret-file: dmFsdWUtMg0KDQo= +--- +apiVersion: v1 +kind: Pod +metadata: + name: secret-dotfiles-pod +spec: + volumes: + - name: secret-volume + secret: + secretName: dotfile-secret + containers: + - name: dotfile-test-container + image: k8s.gcr.io/busybox + command: + - ls + - "-l" + - "/etc/secret-volume" + volumeMounts: + - name: secret-volume + readOnly: true + mountPath: "/etc/secret-volume" +``` + + +卷中会包含一个名为 `.secret-file` 的文件,并且容器 `dotfile-test-container` +中此文件位于路径 `/etc/secret-volume/.secret-file` 处。 + +{{< note >}} + +以句点开头的文件会在 `ls -l` 的输出中被隐藏起来; +列举目录内容时你必须使用 `ls -la` 才能看到它们。 +{{< /note >}} + + +### 使用场景:仅对 Pod 中一个容器可见的 Secret + +考虑一个需要处理 HTTP 请求,执行某些复杂的业务逻辑,之后使用 HMAC +来对某些消息进行签名的程序。因为这一程序的应用逻辑很复杂, +其中可能包含未被注意到的远程服务器文件读取漏洞, +这种漏洞可能会把私钥暴露给攻击者。 + + +这一程序可以分隔成两个容器中的两个进程:前端容器要处理用户交互和业务逻辑, +但无法看到私钥;签名容器可以看到私钥,并对来自前端的简单签名请求作出响应 +(例如,通过本地主机网络)。 + + +采用这种划分的方法,攻击者现在必须欺骗应用服务器来做一些其他操作, +而这些操作可能要比读取一个文件要复杂很多。 + ## Secret 的类型 {#secret-types} -创建 Secret 时,你可以使用 Secret 资源的 `type` 字段, -或者与其等价的 `kubectl` 命令行参数(如果有的话)为其设置类型。 -Secret 的 `type` 有助于对不同类型机密数据的编程处理。 +创建 Secret 时,你可以使用 [Secret](/docs/reference/kubernetes-api/config-and-storage-resources/secret-v1/) +资源的 `type` 字段,或者与其等价的 `kubectl` 命令行参数(如果有的话)为其设置类型。 +Secret 类型有助于对 Secret 数据进行编程处理。 Kubernetes 提供若干种内置的类型,用于一些常见的使用场景。 针对这些类型,Kubernetes 所执行的合法性检查操作以及对其所实施的限制各不相同。 @@ -171,15 +1380,27 @@ Kubernetes 提供若干种内置的类型,用于一些常见的使用场景。 +通过为 Secret 对象的 `type` 字段设置一个非空的字符串值,你也可以定义并使用自己 +Secret 类型。如果 `type` 值为空字符串,则被视为 `Opaque` 类型。 + + -通过为 Secret 对象的 `type` 字段设置一个非空的字符串值,你也可以定义并使用自己 -Secret 类型。如果 `type` 值为空字符串,则被视为 `Opaque` 类型。 Kubernetes 并不对类型的名称作任何限制。不过,如果你要使用内置类型之一, 则你必须满足为该类型所定义的所有要求。 + +如果你要定义一种公开使用的 Secret 类型,请遵守 Secret 类型的约定和结构, +在类型名签名添加域名,并用 `/` 隔开。 +例如:`cloud-hosting.example.net/cloud-api-credentials`。 + ### 服务账号令牌 Secret {#service-account-token-secrets} 类型为 `kubernetes.io/service-account-token` 的 Secret 用来存放标识某 -服务账号的令牌。使用这种 Secret 类型时,你需要确保对象的注解 -`kubernetes.io/service-account-name` 被设置为某个已有的服务账号名称。 -某个 Kubernetes 控制器会填写 Secret 的其它字段,例如 -`kubernetes.io/service-account.uid` 注解以及 `data` 字段中的 `token` -键值,使之包含实际的令牌内容。 +{{< glossary_tooltip text="服务账号" term_id="service-account" >}}的令牌。 +使用这种 Secret 类型时,你需要确保对象的注解 `kubernetes.io/service-account-name` +被设置为某个已有的服务账号名称。某个 Kubernetes +{{< glossary_tooltip text="控制器" term_id="controller" >}}会填写 Secret +的其它字段,例如 `kubernetes.io/service-account.uid` 注解以及 `data` 字段中的 +`token` 键值,使之包含实际的令牌内容。 下面的配置实例声明了一个服务账号令牌 Secret: @@ -268,9 +1494,9 @@ data: ``` -`kubernetes.io/dockercfg` 是一种保留类型,用来存放 `~/.dockercfg` 文件的 -序列化形式。该文件是配置 Docker 命令行的一种老旧形式。 -使用此 Secret 类型时,你需要确保 Secret 的 `data` 字段中包含名为 -`.dockercfg` 的主键,其对应键值是用 base64 编码的某 `~/.dockercfg` -文件的内容。 +`kubernetes.io/dockercfg` 是一种保留类型,用来存放 `~/.dockercfg` 文件的序列化形式。 +该文件是配置 Docker 命令行的一种老旧形式。使用此 Secret 类型时,你需要确保 +Secret 的 `data` 字段中包含名为 `.dockercfg` 的主键,其对应键值是用 base64 +编码的某 `~/.dockercfg` 文件的内容。 类型 `kubernetes.io/dockerconfigjson` 被设计用来保存 JSON 数据的序列化形式, -该 JSON 也遵从 `~/.docker/config.json` 文件的格式规则,而后者是 -`~/.dockercfg` 的新版本格式。 -使用此 Secret 类型时,Secret 对象的 `data` 字段必须包含 `.dockerconfigjson` -键,其键值为 base64 编码的字符串包含 `~/.docker/config.json` 文件的内容。 +该 JSON 也遵从 `~/.docker/config.json` 文件的格式规则,而后者是 `~/.dockercfg` +的新版本格式。使用此 Secret 类型时,Secret 对象的 `data` 字段必须包含 +`.dockerconfigjson` 键,其键值为 base64 编码的字符串包含 `~/.docker/config.json` +文件的内容。 下面是一个 `kubernetes.io/dockercfg` 类型 Secret 的示例: @@ -376,25 +1601,24 @@ to create a Docker registry Secret, you can do: ```shell kubectl create secret docker-registry secret-tiger-docker \ + --docker-email=tiger@acme.example \ --docker-username=tiger \ --docker-password=pass113 \ - --docker-email=tiger@acme.com + --docker-server=my-registry.example:5000 ``` 上面的命令创建一个类型为 `kubernetes.io/dockerconfigjson` 的 Secret。 -如果你对 `data` 字段中的 `.dockerconfigjson` 内容进行转储,你会得到下面的 -JSON 内容,而这一内容是一个合法的 Docker 配置文件。 +如果你对 `.data.dockerconfigjson` 内容进行转储并执行 base64 解码: ```json { "auths": { - "https://index.docker.io/v1/": { + "my-registry.example:5000": { "username": "tiger", "password": "pass113", "email": "tiger@acme.com", @@ -404,6 +1628,15 @@ JSON 内容,而这一内容是一个合法的 Docker 配置文件。 } ``` +{{< note >}} + +`auths` 值是 base64 编码的,其内容被屏蔽但未被加密。 +任何能够读取该 Secret 的人都可以了解镜像库的访问令牌。 +{{< /note >}} + -提供基本身份认证类型的 Secret 仅仅是出于用户方便性考虑。 +提供基本身份认证类型的 Secret 仅仅是出于方便性考虑。 你也可以使用 `Opaque` 类型来保存用于基本身份认证的凭据。 -不过,使用内置的 Secret 类型的有助于对凭据格式进行归一化处理,并且 -API 服务器确实会检查 Secret 配置中是否提供了所需要的主键。 +不过,使用预定义的、公开的 Secret 类型(`kubernetes.io/basic-auth`) +有助于帮助其他用户理解 Secret 的目的,并且对其中存在的主键形成一种约定。 +API 服务器会检查 Secret 配置中是否提供了所需要的主键。 ### SSH 身份认证 Secret {#ssh-authentication-secrets} @@ -472,7 +1709,7 @@ Kubernetes 所提供的内置类型 `kubernetes.io/ssh-auth` 用来存放 SSH 所需要的凭据。使用这种 Secret 类型时,你就必须在其 `data` (或 `stringData`) 字段中提供一个 `ssh-privatekey` 键值对,作为要使用的 SSH 凭据。 -下面的 YAML 是一个 SSH 身份认证 Secret 的配置示例: +下面的清单是一个 SSH 公钥/私钥身份认证的 Secret 示例: ```yaml apiVersion: v1 @@ -488,23 +1725,26 @@ data: 提供 SSH 身份认证类型的 Secret 仅仅是出于用户方便性考虑。 你也可以使用 `Opaque` 类型来保存用于 SSH 身份认证的凭据。 -不过,使用内置的 Secret 类型的有助于对凭据格式进行归一化处理,并且 +不过,使用预定义的、公开的 Secret 类型(`kubernetes.io/ssh-auth`) +有助于其他人理解你的 Secret 的用途,也可以就其中包含的主键名形成约定。 API 服务器确实会检查 Secret 配置中是否提供了所需要的主键。 +{{< caution >}} -{{< caution >}} SSH 私钥自身无法建立 SSH 客户端与服务器端之间的可信连接。 需要其它方式来建立这种信任关系,以缓解“中间人(Man In The Middle)” 攻击,例如向 ConfigMap 中添加一个 `known_hosts` 文件。 @@ -514,9 +1754,11 @@ SSH 私钥自身无法建立 SSH 客户端与服务器端之间的可信连接 ### TLS secrets Kubernetes provides a builtin Secret type `kubernetes.io/tls` for storing -a certificate and its associated key that are typically used for TLS . This -data is primarily used with TLS termination of the Ingress resource, but may -be used with other resources or directly by a workload. +a certificate and its associated key that are typically used for TLS. + +One common use for TLS secrets is to configure encryption in transit for +an [Ingress](/docs/concepts/services-networking/ingress/), but you can also use it +with other resources or directly in your workload. When using this type of Secret, the `tls.key` and the `tls.crt` key must be provided in the `data` (or `stringData`) field of the Secret configuration, although the API server doesn't actually validate the values for each key. @@ -525,12 +1767,12 @@ The following YAML contains an example config for a TLS Secret: --> ### TLS Secret -Kubernetes 提供一种内置的 `kubernetes.io/tls` Secret 类型,用来存放证书 -及其相关密钥(通常用在 TLS 场合)。 -此类数据主要提供给 Ingress 资源,用以终结 TLS 链接,不过也可以用于其他 -资源或者负载。当使用此类型的 Secret 时,Secret 配置中的 `data` (或 -`stringData`)字段必须包含 `tls.key` 和 `tls.crt` 主键,尽管 API 服务器 -实际上并不会对每个键的取值作进一步的合法性检查。 +Kubernetes 提供一种内置的 `kubernetes.io/tls` Secret 类型,用来存放 TLS +场合通常要使用的证书及其相关密钥。 +TLS Secret 的一种典型用法是为 [Ingress](/zh/docs/concepts/services-networking/ingress/) +资源配置传输过程中的数据加密,不过也可以用于其他资源或者直接在负载中使用。 +当使用此类型的 Secret 时,Secret 配置中的 `data` (或 `stringData`)字段必须包含 +`tls.key` 和 `tls.crt` 主键,尽管 API 服务器实际上并不会对每个键的取值作进一步的合法性检查。 下面的 YAML 包含一个 TLS Secret 的配置示例: @@ -573,18 +1815,36 @@ kubectl create secret tls my-tls-secret \ -这里的公钥/私钥对都必须事先已存在。用于 `--cert` 的公钥证书必须是 .PEM 编码的 -(Base64 编码的 DER 格式),且与 `--key` 所给定的私钥匹配。 -私钥必须是通常所说的 PEM 私钥格式,且未加密。对这两个文件而言,PEM 格式数据 -的第一行和最后一行(例如,证书所对应的 `--------BEGIN CERTIFICATE-----` 和 -`-------END CERTIFICATE----`)都不会包含在其中。 +这里的公钥/私钥对都必须事先已存在。用于 `--cert` 的公钥证书必须是 +[RFC 7468 中 5.1 节](https://datatracker.ietf.org/doc/html/rfc7468#section-5.1) +中所规定的 DER 格式,且与 `--key` 所给定的私钥匹配。 +私钥必须是 DER 格式的 PKCS #8 +(参见 [RFC 7468 第 11节](https://datatracker.ietf.org/doc/html/rfc7468#section-11))。 + +{{< note >}} + +类型为 `kubernetes.io/tls` 的 Secret 中包含密钥和证书的 DER 数据,以 Base64 格式编码。 +如果你熟悉私钥和证书的 PEM 格式,base64 与该格式相同,只是你需要略过 PEM +数据中所包含的第一行和最后一行。 + + +例如,对于证书而言,你 **不要** 包含 `--------BEGIN CERTIFICATE-----` +和 `-------END CERTIFICATE----` 这两行。 +{{< /note >}} + -## 创建 Secret {#creating-a-secret} - -有几种不同的方式来创建 Secret: - -- [使用 `kubectl` 命令创建 Secret](/zh/docs/tasks/configmap-secret/managing-secret-using-kubectl/) -- [使用配置文件来创建 Secret](/zh/docs/tasks/configmap-secret/managing-secret-using-config-file/) -- [使用 kustomize 来创建 Secret](/zh/docs/tasks/configmap-secret/managing-secret-using-kustomize/) - - -## 编辑 Secret {#editing-a-secret} - -你可以通过下面的命令编辑现有的 Secret: - -```shell -kubectl edit secrets mysecret -``` - - -这一命令会打开默认的编辑器,允许你更新 `data` 字段中包含的 -base64 编码的 Secret 值: - -```yaml -# Please edit the object below. Lines beginning with a '#' will be ignored, -# and an empty file will abort the edit. If an error occurs while saving this file will be -# reopened with the relevant failures. -# -apiVersion: v1 -data: - username: YWRtaW4= - password: MWYyZDFlMmU2N2Rm -kind: Secret -metadata: - annotations: - kubectl.kubernetes.io/last-applied-configuration: { ... } - creationTimestamp: 2016-01-22T18:41:56Z - name: mysecret - namespace: default - resourceVersion: "164619" - uid: cfee02d6-c137-11e5-8d73-42010af00002 -type: Opaque -``` - - -## 使用 Secret {#using-secrets} - -Secret 可以作为数据卷被挂载,或作为{{< glossary_tooltip text="环境变量" term_id="container-env-variables" >}} -暴露出来以供 Pod 中的容器使用。它们也可以被系统的其他部分使用,而不直接暴露在 Pod 内。 -例如,它们可以保存凭据,系统的其他部分将用它来代表你与外部系统进行交互。 - - - -### 在 Pod 中使用 Secret 文件 {#using-secrets-as-files-from-a-pod} - -在 Pod 中使用存放在卷中的 Secret: - -1. 创建一个 Secret 或者使用已有的 Secret。多个 Pod 可以引用同一个 Secret。 -1. 修改你的 Pod 定义,在 `spec.volumes[]` 下增加一个卷。可以给这个卷随意命名, - 它的 `spec.volumes[].secret.secretName` 必须是 Secret 对象的名字。 -1. 将 `spec.containers[].volumeMounts[]` 加到需要用到该 Secret 的容器中。 - 指定 `spec.containers[].volumeMounts[].readOnly = true` 和 - `spec.containers[].volumeMounts[].mountPath` 为你想要该 Secret 出现的尚未使用的目录。 -1. 修改你的镜像并且/或者命令行,让程序从该目录下寻找文件。 - Secret 的 `data` 映射中的每一个键都对应 `mountPath` 下的一个文件名。 - -这是一个在 Pod 中使用存放在挂载卷中 Secret 的例子: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: mypod -spec: - containers: - - name: mypod - image: redis - volumeMounts: - - name: foo - mountPath: "/etc/foo" - readOnly: true - volumes: - - name: foo - secret: - secretName: mysecret -``` - - -您想要用的每个 Secret 都需要在 `spec.volumes` 中引用。 - -如果 Pod 中有多个容器,每个容器都需要自己的 `volumeMounts` 配置块, -但是每个 Secret 只需要一个 `spec.volumes`。 - -您可以打包多个文件到一个 Secret 中,或者使用的多个 Secret,怎样方便就怎样来。 - -#### 将 Secret 键名映射到特定路径 - -我们还可以控制 Secret 键名在存储卷中映射的的路径。 -你可以使用 `spec.volumes[].secret.items` 字段修改每个键对应的目标路径: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: mypod -spec: - containers: - - name: mypod - image: redis - volumeMounts: - - name: foo - mountPath: "/etc/foo" - readOnly: true - volumes: - - name: foo - secret: - secretName: mysecret - items: - - key: username - path: my-group/my-username -``` - - -将会发生什么呢: - -- `username` Secret 存储在 `/etc/foo/my-group/my-username` 文件中而不是 `/etc/foo/username` 中。 -- `password` Secret 没有被映射 - -如果使用了 `spec.volumes[].secret.items`,只有在 `items` 中指定的键会被映射。 -要使用 Secret 中所有键,就必须将它们都列在 `items` 字段中。 -所有列出的键名必须存在于相应的 Secret 中。否则,不会创建卷。 - -#### Secret 文件权限 - -你还可以指定 Secret 将拥有的权限模式位。如果不指定,默认使用 `0644`。 -你可以为整个 Secret 卷指定默认模式;如果需要,可以为每个密钥设定重载值。 - -例如,您可以指定如下默认模式: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: mypod -spec: - containers: - - name: mypod - image: redis - volumeMounts: - - name: foo - mountPath: "/etc/foo" - volumes: - - name: foo - secret: - secretName: mysecret - defaultMode: 256 -``` - - -之后,Secret 将被挂载到 `/etc/foo` 目录,而所有通过该 Secret 卷挂载 -所创建的文件的权限都是 `0400`。 - -请注意,JSON 规范不支持八进制符号,因此使用 256 值作为 0400 权限。 -如果你使用 YAML 而不是 JSON,则可以使用八进制符号以更自然的方式指定权限。 - - -注意,如果你通过 `kubectl exec` 进入到 Pod 中,你需要沿着符号链接来找到 -所期望的文件模式。例如,下面命令检查 Secret 文件的访问模式: - -```shell -kubectl exec mypod -it sh - -cd /etc/foo -ls -l -``` - - -输出类似于: - -``` -total 0 -lrwxrwxrwx 1 root root 15 May 18 00:18 password -> ..data/password -lrwxrwxrwx 1 root root 15 May 18 00:18 username -> ..data/username -``` - - -沿着符号链接,可以查看文件的访问模式: - -```shell -cd /etc/foo/..data -ls -l -``` - - -输出类似于: - -``` -total 8 --r-------- 1 root root 12 May 18 00:18 password --r-------- 1 root root 5 May 18 00:18 username -``` - - - -你还可以使用映射,如上一个示例,并为不同的文件指定不同的权限,如下所示: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: mypod -spec: - containers: - - name: mypod - image: redis - volumeMounts: - - name: foo - mountPath: "/etc/foo" - volumes: - - name: foo - secret: - secretName: mysecret - items: - - key: username - path: my-group/my-username - mode: 511 -``` - - -在这里,位于 `/etc/foo/my-group/my-username` 的文件的权限值为 `0777`。 -由于 JSON 限制,必须以十进制格式指定模式,即 `511`。 - -请注意,如果稍后读取此权限值,可能会以十进制格式显示。 - -#### 使用来自卷中的 Secret 值 {#consuming-secret-values-from-volumes} - -在挂载了 Secret 卷的容器内,Secret 键名显示为文件名,并且 Secret 的值 -使用 base-64 解码后存储在这些文件中。 -这是在上面的示例容器内执行的命令的结果: - -```shell -ls /etc/foo/ -``` - - -输出类似于: - -``` -username -password -``` - -```shell -cat /etc/foo/username -``` - - -输出类似于: - -``` -admin -``` - -```shell -cat /etc/foo/password -``` - - -输出类似于: - -``` -1f2d1e2e67df -``` - - -容器中的程序负责从文件中读取 secret。 - - -#### 挂载的 Secret 会被自动更新 - -当已经存储于卷中被使用的 Secret 被更新时,被映射的键也将终将被更新。 -组件 kubelet 在周期性同步时检查被挂载的 Secret 是不是最新的。 -但是,它会使用其本地缓存的数值作为 Secret 的当前值。 - -缓存的类型可以使用 [KubeletConfiguration 结构](/zh/docs/reference/config-api/kubelet-config.v1beta1/) -中的 `ConfigMapAndSecretChangeDetectionStrategy` 字段来配置。 -它可以通过 watch 操作来传播(默认),基于 TTL 来刷新,也可以 -将所有请求直接重定向到 API 服务器。 -因此,从 Secret 被更新到将新 Secret 被投射到 Pod 的那一刻的总延迟可能与 -kubelet 同步周期 + 缓存传播延迟一样长,其中缓存传播延迟取决于所选的缓存类型。 -对应于不同的缓存类型,该延迟或者等于 watch 传播延迟,或者等于缓存的 TTL, -或者为 0。 - - -{{< note >}} -使用 Secret 作为[子路径](/zh/docs/concepts/storage/volumes#using-subpath)卷挂载的容器 -不会收到 Secret 更新。 -{{< /note >}} - - -#### 以环境变量的形式使用 Secrets {#using-secrets-as-environment-variables} - -将 Secret 作为 Pod 中的{{< glossary_tooltip text="环境变量" term_id="container-env-variables" >}}使用: - -1. 创建一个 Secret 或者使用一个已存在的 Secret。多个 Pod 可以引用同一个 Secret。 -1. 修改 Pod 定义,为每个要使用 Secret 的容器添加对应 Secret 键的环境变量。 - 使用 Secret 键的环境变量应在 `env[x].valueFrom.secretKeyRef` 中指定 - 要包含的 Secret 名称和键名。 -1. 更改镜像并/或者命令行,以便程序在指定的环境变量中查找值。 - -这是一个使用来自环境变量中的 Secret 值的 Pod 示例: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: secret-env-pod -spec: - containers: - - name: mycontainer - image: redis - env: - - name: SECRET_USERNAME - valueFrom: - secretKeyRef: - name: mysecret - key: username - - name: SECRET_PASSWORD - valueFrom: - secretKeyRef: - name: mysecret - key: password - restartPolicy: Never -``` - - -#### 使用来自环境变量的 Secret 值 {#consuming-secret-values-from-environment-variables} - -在一个以环境变量形式使用 Secret 的容器中,Secret 键表现为常规的环境变量,其中 -包含 Secret 数据的 base-64 解码值。这是从上面的示例在容器内执行的命令的结果: - -```shell -echo $SECRET_USERNAME -``` - - -输出类似于: - -``` -admin -``` - -```shell -echo $SECRET_PASSWORD -``` - - -输出类似于: - -``` -1f2d1e2e67df -``` - - -#### Secret 更新之后对应的环境变量不会被更新 - -如果某个容器已经在通过环境变量使用某 Secret,对该 Secret 的更新不会被 -容器马上看见,除非容器被重启。有一些第三方的解决方案能够在 Secret 发生 -变化时触发容器重启。 - @@ -1225,33 +1970,30 @@ There are third party solutions for triggering restarts when secrets change. {{< feature-state for_k8s_version="v1.21" state="stable" >}} -Kubernetes 的特性 _不可变的 Secret 和 ConfigMap_ 提供了一种可选配置, -可以设置各个 Secret 和 ConfigMap 为不可变的。 -对于大量使用 Secret 的集群(至少有成千上万各不相同的 Secret 供 Pod 挂载), -禁止变更它们的数据有下列好处: +Kubernetes 允许你将特定的 Secret(和 ConfigMap)标记为 **不可更改(Immutable)**。 +禁止更改现有 Secret 的数据有下列好处: - 防止意外(或非预期的)更新导致应用程序中断 -- 通过将 Secret 标记为不可变来关闭 kube-apiserver 对其的监视,从而显著降低 - kube-apiserver 的负载,提升集群性能。 +- (对于大量使用 Secret 的集群而言,至少数万个不同的 Secret 供 Pod 挂载), + 通过将 Secret 标记为不可变,可以极大降低 kube-apiserver 的负载,提升集群性能。 + kubelet 不需要监视那些被标记为不可更改的 Secret。 -这个特性通过 `ImmutableEmphemeralVolumes` -[特性门控](/zh/docs/reference/command-line-tools-reference/feature-gates/) -来控制,从 v1.19 开始默认启用。 +### 将 Secret 标记为不可更改 {#secret-immutable-create} + 你可以通过将 Secret 的 `immutable` 字段设置为 `true` 创建不可更改的 Secret。 例如: @@ -1265,6 +2007,11 @@ data: immutable: true ``` + +你也可以更改现有的 Secret,令其不可更改。 + {{< note >}} -一旦一个 Secret 或 ConfigMap 被标记为不可更改,撤销此操作或者更改 `data` 字段的内容都是 _不_ 可能的。 -只能删除并重新创建这个 Secret。现有的 Pod 将维持对已删除 Secret 的挂载点 - 建议重新创建这些 Pod。 +一旦一个 Secret 或 ConfigMap 被标记为不可更改,撤销此操作或者更改 `data` +字段的内容都是 **不** 可能的。 +只能删除并重新创建这个 Secret。现有的 Pod 将维持对已删除 Secret 的挂载点 -- +建议重新创建这些 Pod。 {{< /note >}} -#### 使用 imagePullSecret {#using-imagepullsecrets} +## Secret 的信息安全问题 -`imagePullSecrets` 字段中包含一个列表,列举对同一名字空间中的 Secret 的引用。 -你可以使用 `imagePullSecrets` 将包含 Docker(或其他)镜像仓库密码的 Secret 传递给 -kubelet。kubelet 使用此信息来替你的 Pod 拉取私有镜像。 -关于 `imagePullSecrets` 字段的更多信息,请参考 -[PodSpec API](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#podspec-v1-core) 文档。 - -#### 手动指定 imagePullSecret - -你可以阅读[容器镜像文档](/zh/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod) -以了解如何设置 `imagePullSecrets`。 - - -#### 设置自动附加 imagePullSecrets - -您可以手动创建 `imagePullSecret`,并在 ServiceAccount 中引用它。 -使用该 ServiceAccount 创建的任何 Pod 和默认使用该 ServiceAccount 的 -Pod 将会将其的 imagePullSecret 字段设置为服务帐户的 imagePullSecret 值。 -有关该过程的详细说明,请参阅 -[将 ImagePullSecrets 添加到服务帐户](/zh/docs/tasks/configure-pod-container/configure-service-account/#adding-imagepullsecrets-to-a-service-account)。 - - - -## 详细说明 {#details} - -### 限制 {#restrictions} - -Kubernetes 会验证 Secret 作为卷来源时所给的对象引用确实指向一个类型为 -Secret 的对象。因此,Secret 需要先于任何依赖于它的 Pod 创建。 - -Secret API 对象处于某{{< glossary_tooltip text="名字空间" term_id="namespace" >}} -中。它们只能由同一命名空间中的 Pod 引用。 - - -每个 Secret 的大小限制为 1MB。这是为了防止创建非常大的 Secret 导致 API 服务器 -和 kubelet 的内存耗尽。然而,创建过多较小的 Secret 也可能耗尽内存。 -更全面得限制 Secret 内存用量的功能还在计划中。 - -kubelet 仅支持从 API 服务器获得的 Pod 使用 Secret。 -这包括使用 `kubectl` 创建的所有 Pod,以及间接通过副本控制器创建的 Pod。 -它不包括通过 kubelet `--manifest-url` 标志,`--config` 标志或其 REST API -创建的 Pod(这些不是创建 Pod 的常用方法)。 -{{}} -的 `spec` 不能引用 Secret 或任何其他 API 对象。 - - -以环境变量形式在 Pod 中使用 Secret 之前必须先创建 -Secret,除非该环境变量被标记为可选的。 -Pod 中引用不存在的 Secret 时将无法启动。 - -使用 `secretKeyRef` 时,如果引用了指定 Secret 不存在的键,对应的 Pod 也无法启动。 - -对于通过 `envFrom` 填充环境变量的 Secret,如果 Secret 中包含的键名无法作为 -合法的环境变量名称,对应的键会被跳过,该 Pod 将被允许启动。 -不过这时会产生一个事件,其原因为 `InvalidVariableNames`,其消息中包含被跳过的无效键的列表。 -下面的示例显示一个 Pod,它引用了包含 2 个无效键 1badkey 和 2alsobad。 - -```shell -kubectl get events -``` - - -输出类似于: - -``` -LASTSEEN FIRSTSEEN COUNT NAME KIND SUBOBJECT TYPE REASON -0s 0s 1 dapi-test-pod Pod Warning InvalidEnvironmentVariableNames kubelet, 127.0.0.1 Keys [1badkey, 2alsobad] from the EnvFrom secret default/mysecret were skipped since they are considered invalid environment variable names. -``` - - -### Secret 与 Pod 生命周期的关系 - -通过 API 创建 Pod 时,不会检查引用的 Secret 是否存在。一旦 Pod 被调度,kubelet -就会尝试获取该 Secret 的值。如果获取不到该 Secret,或者暂时无法与 API 服务器建立连接, -kubelet 将会定期重试。kubelet 将会报告关于 Pod 的事件,并解释它无法启动的原因。 -一旦获取到 Secret,kubelet 将创建并挂载一个包含它的卷。在 Pod 的所有卷被挂载之前, -Pod 中的容器不会启动。 - - -## 使用案例 - - -### 案例:以环境变量的形式使用 Secret - - -创建一个 Secret 定义: - -```yaml -apiVersion: v1 -kind: Secret -metadata: - name: mysecret -type: Opaque -data: - USER_NAME: YWRtaW4= - PASSWORD: MWYyZDFlMmU2N2Rm -``` - - -生成 Secret 对象: - -```shell -kubectl apply -f mysecret.yaml -``` - - -使用 `envFrom` 将 Secret 的所有数据定义为容器的环境变量。 -Secret 中的键名称为 Pod 中的环境变量名称: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: secret-test-pod -spec: - containers: - - name: test-container - image: k8s.gcr.io/busybox - command: [ "/bin/sh", "-c", "env" ] - envFrom: - - secretRef: - name: mysecret - restartPolicy: Never -``` - - -### 案例:包含 SSH 密钥的 Pod - -创建一个包含 SSH 密钥的 Secret: - -```shell -kubectl create secret generic ssh-key-secret \ - --from-file=ssh-privatekey=/path/to/.ssh/id_rsa \ - --from-file=ssh-publickey=/path/to/.ssh/id_rsa.pub -``` - - -输出类似于: - -``` -secret "ssh-key-secret" created -``` - - -你也可以创建一个带有包含 SSH 密钥的 `secretGenerator` 字段的 -`kustomization.yaml` 文件。 - - -{{< caution >}} -发送自己的 SSH 密钥之前要仔细思考:集群的其他用户可能有权访问该密钥。 -你可以使用一个服务帐户,分享给 Kubernetes 集群中合适的用户,这些用户是你要分享的。 -如果服务账号遭到侵犯,可以将其收回。 -{{< /caution >}} - - -现在我们可以创建一个 Pod,令其引用包含 SSH 密钥的 Secret,并通过存储卷来使用它: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: secret-test-pod - labels: - name: secret-test -spec: - volumes: - - name: secret-volume - secret: - secretName: ssh-key-secret - containers: - - name: ssh-test-container - image: mySshImage - volumeMounts: - - name: secret-volume - readOnly: true - mountPath: "/etc/secret-volume" -``` - - -容器中的命令运行时,密钥的片段可以在以下目录找到: - -``` -/etc/secret-volume/ssh-publickey -/etc/secret-volume/ssh-privatekey -``` - - -然后容器可以自由使用 Secret 数据建立一个 SSH 连接。 - - -### 案例:包含生产/测试凭据的 Pod - -下面的例子展示的是两个 Pod。 -一个 Pod 使用包含生产环境凭据的 Secret,另一个 Pod 使用包含测试环境凭据的 Secret。 - -你可以创建一个带有 `secretGenerator` 字段的 `kustomization.yaml` -文件,或者执行 `kubectl create secret`: - -```shell -kubectl create secret generic prod-db-secret \ - --from-literal=username=produser \ - --from-literal=password=Y4nys7f11 -``` - - -输出类似于: - -``` -secret "prod-db-secret" created -``` - -```shell -kubectl create secret generic test-db-secret \ - --from-literal=username=testuser \ - --from-literal=password=iluvtests -``` - - -输出类似于: - -``` -secret "test-db-secret" created -``` - - -{{< note >}} -特殊字符(例如 `$`、`\`、`*`、`=` 和 `!`)会被你的 -[Shell](https://en.wikipedia.org/wiki/Shell_(computing))解释,因此需要转义。 -在大多数 Shell 中,对密码进行转义的最简单方式是用单引号(`'`)将其括起来。 -例如,如果您的实际密码是 `S!B\*d$zDsb`,则应通过以下方式执行命令: - -```shell -kubectl create secret generic dev-db-secret --from-literal=username=devuser --from-literal=password='S!B\*d$zDsb=' -``` - -您无需对文件中的密码(`--from-file`)中的特殊字符进行转义。 -{{< /note >}} - - -创建 pod : - -```shell -$ cat < pod.yaml -apiVersion: v1 -kind: List -items: -- kind: Pod - apiVersion: v1 - metadata: - name: prod-db-client-pod - labels: - name: prod-db-client - spec: - volumes: - - name: secret-volume - secret: - secretName: prod-db-secret - containers: - - name: db-client-container - image: myClientImage - volumeMounts: - - name: secret-volume - readOnly: true - mountPath: "/etc/secret-volume" -- kind: Pod - apiVersion: v1 - metadata: - name: test-db-client-pod - labels: - name: test-db-client - spec: - volumes: - - name: secret-volume - secret: - secretName: test-db-secret - containers: - - name: db-client-container - image: myClientImage - volumeMounts: - - name: secret-volume - readOnly: true - mountPath: "/etc/secret-volume" -EOF -``` - - -将 Pod 添加到同一个 kustomization.yaml 文件 - -```shell -$ cat <> kustomization.yaml -resources: -- pod.yaml -EOF -``` - - -通过下面的命令应用所有对象 - -```shell -kubectl apply -k . -``` - - -两个容器都会在其文件系统上存在以下文件,其中包含容器对应的环境的值: - -``` -/etc/secret-volume/username -/etc/secret-volume/password -``` - - -请注意,两个 Pod 的规约配置中仅有一个字段不同;这有助于使用共同的 Pod 配置模板创建 -具有不同能力的 Pod。 - -您可以使用两个服务账号进一步简化基本的 Pod 规约: - -1. 名为 `prod-user` 的服务账号拥有 `prod-db-secret` -1. 名为 `test-user` 的服务账号拥有 `test-db-secret` - -然后,Pod 规约可以缩短为: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: prod-db-client-pod - labels: - name: prod-db-client -spec: - serviceAccount: prod-db-client - containers: - - name: db-client-container - image: myClientImage -``` - - -### 案例:Secret 卷中以句点号开头的文件 - -你可以通过定义以句点开头的键名,将数据“隐藏”起来。 -例如,当如下 Secret 被挂载到 `secret-volume` 卷中: - -```yaml -apiVersion: v1 -kind: Secret -metadata: - name: dotfile-secret -data: - .secret-file: dmFsdWUtMg0KDQo= ---- -apiVersion: v1 -kind: Pod -metadata: - name: secret-dotfiles-pod -spec: - volumes: - - name: secret-volume - secret: - secretName: dotfile-secret - containers: - - name: dotfile-test-container - image: k8s.gcr.io/busybox - command: - - ls - - "-l" - - "/etc/secret-volume" - volumeMounts: - - name: secret-volume - readOnly: true - mountPath: "/etc/secret-volume" -``` - - - -卷中将包含唯一的叫做 `.secret-file` 的文件。 -容器 `dotfile-test-container` 中,该文件处于 `/etc/secret-volume/.secret-file` 路径下。 - - -{{< note >}} -以点号开头的文件在 `ls -l` 的输出中会被隐藏起来; -列出目录内容时,必须使用 `ls -la` 才能看到它们。 -{{< /note >}} - - -### 案例:Secret 仅对 Pod 中的一个容器可见 {#secret-visible-to-only-one-container} -考虑一个需要处理 HTTP 请求、执行一些复杂的业务逻辑,然后使用 HMAC 签署一些消息的应用。 -因为应用程序逻辑复杂,服务器中可能会存在一个未被注意的远程文件读取漏洞, -可能会将私钥暴露给攻击者。 - - -解决的办法可以是将应用分为两个进程,分别运行在两个容器中: -前端容器,用于处理用户交互和业务逻辑,但无法看到私钥; -签名容器,可以看到私钥,响应来自前端(例如通过本地主机网络)的简单签名请求。 - -使用这种分割方法,攻击者现在必须欺骗应用程序服务器才能进行任意的操作, -这可能比使其读取文件更难。 - - - - -## 最佳实践 {#best-practices} - -### 客户端使用 Secret API - -当部署与 Secret API 交互的应用程序时,应使用 -[鉴权策略](/zh/docs/reference/access-authn-authz/authorization/), -例如 [RBAC](/zh/docs/reference/access-authn-authz/rbac/),来限制访问。 +尽管 ConfigMap 和 Secret 的工作方式类似,但 Kubernetes 对 Secret 有一些额外的保护。 - -Secret 中的值对于不同的环境来说重要性可能不同。 -很多 Secret 都可能导致 Kubernetes 集群内部的权限越界(例如服务账号令牌) -甚至逃逸到集群外部。 -即使某一个应用程序可以就所交互的 Secret 的能力作出正确抉择,但是同一命名空间中 -的其他应用程序却可能不这样做。 - -由于这些原因,在命名空间中 `watch` 和 `list` Secret 的请求是非常强大的能力, -是应该避免的行为。列出 Secret 的操作可以让客户端检查该命名空间中存在的所有 Secret。 -在群集中 `watch` 和 `list` 所有 Secret 的能力应该只保留给特权最高的系统级组件。 +Secret 通常保存重要性各异的数值,其中很多都可能会导致 Kubernetes 中 +(例如,服务账号令牌)或对外部系统的特权提升。 +即使某些个别应用能够推导它期望使用的 Secret 的能力, +同一名字空间中的其他应用可能会让这种假定不成立。 -需要访问 Secret API 的应用程序应该针对所需要的 Secret 执行 `get` 请求。 -这样,管理员就能限制对所有 Secret 的访问,同时为应用所需要的 -[实例设置访问允许清单](/zh/docs/reference/access-authn-authz/rbac/#referring-to-resources) 。 - -为了获得高于轮询操作的性能,客户端设计资源时,可以引用 Secret,然后对资源执行 `watch` -操作,在引用更改时重新检索 Secret。 -此外,社区还存在一种 [“批量监控” API](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/bulk_watch.md) -的提案,允许客户端 `watch` 独立的资源,该功能可能会在将来的 Kubernetes 版本中提供。 +只有当某个节点上的 Pod 需要某 Secret 时,对应的 Secret 才会被发送到该节点上。 +如果将 Secret 挂载到 Pod 中,kubelet 会将数据的副本保存在在 `tmpfs` 中, +这样机密的数据不会被写入到持久性存储中。 +一旦依赖于该 Secret 的 Pod 被删除,kubelet 会删除来自于该 Secret 的机密数据的本地副本。 -## 安全属性 {#security-properties} - -### 保护 {#protections} - -因为 Secret 对象可以独立于使用它们的 Pod 而创建,所以在创建、查看和编辑 Pod 的流程中 -Secret 被暴露的风险较小。系统还可以对 Secret 对象采取额外的预防性保护措施, -例如,在可能的情况下避免将其写到磁盘。 +同一个 Pod 中可能包含多个容器。默认情况下,你所定义的容器只能访问默认 ServiceAccount +及其相关 Secret。你必须显式地定义环境变量或者将卷映射到容器中,才能为容器提供对其他 +Secret 的访问。 -只有当某节点上的 Pod 需要用到某 Secret 时,该 Secret 才会被发送到该节点上。 -Secret 不会被写入磁盘,而是被 kubelet 存储在 tmpfs 中。 -一旦依赖于它的 Pod 被删除,Secret 数据的本地副本就被删除。 +针对同一节点上的多个 Pod 可能有多个 Secret。不过,只有某个 Pod 所请求的 Secret +才有可能对 Pod 中的容器可见。因此,一个 Pod 不会获得访问其他 Pod 的 Secret 的权限。 -同一节点上的很多个 Pod 可能拥有多个 Secret。 -但是,只有 Pod 所请求的 Secret 在其容器中才是可见的。 -因此,一个 Pod 不能访问另一个 Pod 的 Secret。 +{{< warning >}} + +节点上的所有特权容器都可能访问到该节点上使用的所有 Secret。 +{{< /warning >}} -同一个 Pod 中可能有多个容器。但是,Pod 中的每个容器必须通过 `volumeeMounts` -请求挂载 Secret 卷才能使卷中的 Secret 对容器可见。 -这一实现可以用于在 Pod 级别[构建安全分区](#secret-visible-to-only-one-container)。 +### 针对开发人员的安全性建议 -在大多数 Kubernetes 发行版中,用户与 API 服务器之间的通信以及 -从 API 服务器到 kubelet 的通信都受到 SSL/TLS 的保护。 -通过这些通道传输时,Secret 受到保护。 - -{{< feature-state for_k8s_version="v1.13" state="beta" >}} +- 应用在从环境变量或卷中读取了机密信息内容之后仍要对其进行保护。例如, + 你的应用应该避免用明文的方式将 Secret 数据写入日志,或者将其传递给不可信的第三方。 +- 如果你在一个 Pod 中定义了多个容器,而只有一个容器需要访问某 Secret, + 定义卷挂载或环境变量配置时,应确保其他容器无法访问该 Secret。 + +- 如果你通过{{< glossary_tooltip text="清单" term_id="manifest" >}}来配置某 Secret, + Secret 数据以 Base64 的形式编码,将此文件共享,或者将其检入到某源码仓库, + 都意味着 Secret 对于任何可以读取清单的人都是可见的。 + Base64 编码 **不是** 一种加密方法,与明文相比没有任何安全性提升。 + +- 部署与 Secret API 交互的应用时,你应该使用 [RBAC](/zh/docs/reference/access-authn-authz/rbac/) + 这类[鉴权策略](/zh/docs/reference/access-authn-authz/authorization/)来限制访问。 + +- 在 Kubernetes API 中,名字空间内对 Secret 对象的 `watch` 和 `list` 请求是非常强大的能力。 + 在可能的时候应该避免授予这类访问权限,因为通过列举 Secret, + 客户端能够查看对应名字空间内所有 Secret 的取值。 -你可以为 Secret 数据开启[静态加密](/zh/docs/tasks/administer-cluster/encrypt-data/), -这样 Secret 数据就不会以明文形式存储到{{< glossary_tooltip term_id="etcd" >}} 中。 +### 针对集群管理员的安全性建议 + +{{< caution >}} + +能够创建使用 Secret 的 Pod 的用户也可以查看该 Secret 的取值。 +即使集群策略不允许某用户直接读取 Secret 对象,这一用户仍然可以通过运行一个 +Pod 来访问 Secret 的内容。 +{{< /caution >}} -### 风险 +- 保留(使用 Kubernetes API)对集群中所有 Secret 对象执行 `watch` 或 `list` 操作的能力, + 这样只有特权级最高、系统级别的组件能够执行这类操作。 +- 在部署需要通过 Secret API 交互的应用时,你应该通过使用 + [RBAC](/zh/docs/reference/access-authn-authz/rbac/) + 这类[鉴权策略](/zh/docs/reference/access-authn-authz/authorization/)来限制访问。 + +- 在 API 服务器上,对象(包括 Secret)会被持久化到 {{< glossary_tooltip term_id="etcd" >}} 中; + 因此: -- API 服务器上的 Secret 数据以纯文本的方式存储在 etcd 中,因此: - - 管理员应该为集群数据开启静态加密(要求 v1.13 或者更高版本)。 - - 管理员应该限制只有 admin 用户能访问 etcd; - - API 服务器中的 Secret 数据位于 etcd 使用的磁盘上;管理员可能希望在不再使用时擦除/粉碎 etcd 使用的磁盘 - - 如果 etcd 运行在集群内,管理员应该确保 etcd 之间的通信使用 SSL/TLS 进行加密。 -- 如果您将 Secret 数据编码为 base64 的清单(JSON 或 YAML)文件,共享该文件或将其检入代码库,该密码将会被泄露。 Base64 编码不是一种加密方式,应该视同纯文本。 -- 应用程序在从卷中读取 Secret 后仍然需要保护 Secret 的值,例如不会意外将其写入日志或发送给不信任方。 -- 可以创建使用 Secret 的 Pod 的用户也可以看到该 Secret 的值。即使 API 服务器策略不允许用户读取 Secret 对象,用户也可以运行 Pod 导致 Secret 暴露。 + - 只应准许集群管理员访问 etcd(包括只读访问); + - 为 Secret 对象启用[静态加密](/zh/docs/tasks/administer-cluster/encrypt-data/), + 这样这些 Secret 的数据就不会以明文的形式保存到 + {{< glossary_tooltip term_id="etcd" >}} 中; + - 当 etcd 的持久化存储不再被使用时,请考虑彻底擦除存储介质; + - 如果存在多个 etcd 实例,请确保 etcd 使用 SSL/TLS 来完成其对等通信。 ## {{% heading "whatsnext" %}} From 849eed7d0ad030f6e1958d43d0a09e27178ca951 Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Tue, 29 Mar 2022 11:21:58 +0800 Subject: [PATCH 082/102] [zh] Update optional-kubectl-configs-zsh.md Signed-off-by: xin.li --- .../tools/included/optional-kubectl-configs-zsh.md | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/content/zh/docs/tasks/tools/included/optional-kubectl-configs-zsh.md b/content/zh/docs/tasks/tools/included/optional-kubectl-configs-zsh.md index b439db63bc..9a40a829aa 100644 --- a/content/zh/docs/tasks/tools/included/optional-kubectl-configs-zsh.md +++ b/content/zh/docs/tasks/tools/included/optional-kubectl-configs-zsh.md @@ -26,24 +26,19 @@ source <(kubectl completion zsh) ``` -如果你为 kubectl 定义了别名,可以扩展脚本补全,以兼容该别名。 - -```zsh -echo 'alias k=kubectl' >>~/.zshrc -echo 'compdef __start_kubectl k' >>~/.zshrc -``` +如果你为 kubectl 定义了别名,kubectl 自动补全将自动使用它。 重新加载 shell 后,kubectl 自动补全功能将立即生效。 -如果你收到 `complete:13: command not found: compdef` 这样的错误提示,那请将下面内容添加到 `~/.zshrc` 文件的开头: - +如果你收到 `2: command not found: compdef` 这样的错误提示,那请将下面内容添加到 `~/.zshrc` 文件的开头: ```zsh autoload -Uz compinit compinit From 047966418e7928b23b8ee36f13e87e08ae41c8f2 Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Tue, 29 Mar 2022 11:51:15 +0800 Subject: [PATCH 083/102] [zh] update create-cluster_index.md Signed-off-by: xin.li --- .../tutorials/kubernetes-basics/create-cluster/_index.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/content/zh/docs/tutorials/kubernetes-basics/create-cluster/_index.md b/content/zh/docs/tutorials/kubernetes-basics/create-cluster/_index.md index a3e250856e..59dc1385c7 100644 --- a/content/zh/docs/tutorials/kubernetes-basics/create-cluster/_index.md +++ b/content/zh/docs/tutorials/kubernetes-basics/create-cluster/_index.md @@ -2,3 +2,9 @@ title: 创建集群 weight: 10 --- + + +了解 Kubernetes {{}}并使用 Minikube +创建一个简单的集群。 From 62c4ddc8f68ea22816f07c7505d6f30017d793cb Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Tue, 29 Mar 2022 15:35:59 +0800 Subject: [PATCH 084/102] [zh]Update cluster-intro.md Signed-off-by: xin.li --- .../kubernetes-basics/create-cluster/cluster-intro.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/zh/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro.html b/content/zh/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro.html index d6a0d4a9ec..eb1d9eb7ca 100644 --- a/content/zh/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro.html +++ b/content/zh/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro.html @@ -72,7 +72,7 @@ weight: 10

Master 负责管理整个集群。 Master 协调集群中的所有活动,例如调度应用、维护应用的所需状态、应用扩容以及推出新的更新。

-

Node 是一个虚拟机或者物理机,它在 Kubernetes 集群中充当工作机器的角色 每个Node都有 Kubelet , 它管理 Node 而且是 Node 与 Master 通信的代理。 Node 还应该具有用于​​处理容器操作的工具,例如 Docker 或 rkt 。处理生产级流量的 Kubernetes 集群至少应具有三个 Node 。

+

Node 是一个虚拟机或者物理机,它在 Kubernetes 集群中充当工作机器的角色 每个Node都有 Kubelet , 它管理 Node 而且是 Node 与 Master 通信的代理。 Node 还应该具有用于​​处理容器操作的工具,例如 Docker 或 rkt 。处理生产级流量的 Kubernetes 集群至少应具有三个 Node,因为如果一个 Node 出现故障其对应的 etcd 成员和控制平面实例都会丢失,并且冗余会受到影响。 你可以通过添加更多控制平面节点来降低这种风险 。

From 200f5f5e4c8e8c78371777fefcbe4a38228b3b2d Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Tue, 29 Mar 2022 17:52:33 +0800 Subject: [PATCH 085/102] [zh] Update cluster-level-pass.md Signed-off-by: xin.li --- .../zh/docs/tutorials/security/cluster-level-pss.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/content/zh/docs/tutorials/security/cluster-level-pss.md b/content/zh/docs/tutorials/security/cluster-level-pss.md index 0b4721c43b..714bbca1f7 100644 --- a/content/zh/docs/tutorials/security/cluster-level-pss.md +++ b/content/zh/docs/tutorials/security/cluster-level-pss.md @@ -19,7 +19,7 @@ Pod Security admission (PSA) is enabled by default in v1.23 and later, as it has [graduated to beta](/blog/2021/12/09/pod-security-admission-beta/). Pod Security is an admission controller that carries out checks against the Kubernetes -[Pod Security Standards](docs/concepts/security/pod-security-standards/) when new pods are +[Pod Security Standards](/docs/concepts/security/pod-security-standards/) when new pods are created. This tutorial shows you how to enforce the `baseline` Pod Security Standard at the cluster level which applies a standard configuration to all namespaces in a cluster. @@ -406,14 +406,14 @@ following: ## 清理 {#clean-up} -运行 `kind delete cluster -name psa-with-cluster-pss` 和 -`kind delete cluster -name psa-wo-cluster-pss` 来删除你创建的集群。 +运行 `kind delete cluster --name psa-with-cluster-pss` 和 +`kind delete cluster --name psa-wo-cluster-pss` 来删除你创建的集群。 ## {{% heading "whatsnext" %}} From df4728f9cd3f36858ae06050248dce269dca6a46 Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Tue, 29 Mar 2022 18:30:34 +0800 Subject: [PATCH 086/102] [zh] Update pod-configmap-env-var-valueFrom.md Signed-off-by: xin.li --- content/zh/examples/pods/pod-with-node-affinity.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/content/zh/examples/pods/pod-with-node-affinity.yaml b/content/zh/examples/pods/pod-with-node-affinity.yaml index 253d2b21ea..e077f79883 100644 --- a/content/zh/examples/pods/pod-with-node-affinity.yaml +++ b/content/zh/examples/pods/pod-with-node-affinity.yaml @@ -8,11 +8,10 @@ spec: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - - key: kubernetes.io/e2e-az-name + - key: kubernetes.io/os operator: In values: - - e2e-az1 - - e2e-az2 + - linux preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: From 41336b8c0693f36288f41cd0398dd72a7df75305 Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Tue, 29 Mar 2022 19:01:46 +0800 Subject: [PATCH 087/102] [zh] Update pod-configmap-env-var-valueFrom.md Signed-off-by: xin.li --- content/zh/examples/pods/pod-configmap-env-var-valueFrom.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/zh/examples/pods/pod-configmap-env-var-valueFrom.yaml b/content/zh/examples/pods/pod-configmap-env-var-valueFrom.yaml index a72b4335ce..00827ec98a 100644 --- a/content/zh/examples/pods/pod-configmap-env-var-valueFrom.yaml +++ b/content/zh/examples/pods/pod-configmap-env-var-valueFrom.yaml @@ -6,7 +6,7 @@ spec: containers: - name: test-container image: k8s.gcr.io/busybox - command: [ "/bin/sh", "-c", "echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)" ] + command: [ "/bin/echo", "$(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)" ] env: - name: SPECIAL_LEVEL_KEY valueFrom: From ee0d8a0b27e38b486d7036dec4069c8bd94cc64c Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Tue, 29 Mar 2022 19:29:43 +0800 Subject: [PATCH 088/102] [zh] Update zookeeper-pod-disruption-budget-maxunavailable.yaml Signed-off-by: xin.li --- .../policy/zookeeper-pod-disruption-budget-maxunavailable.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/zh/examples/policy/zookeeper-pod-disruption-budget-maxunavailable.yaml b/content/zh/examples/policy/zookeeper-pod-disruption-budget-maxunavailable.yaml index a62bef140f..ef0b8645ba 100644 --- a/content/zh/examples/policy/zookeeper-pod-disruption-budget-maxunavailable.yaml +++ b/content/zh/examples/policy/zookeeper-pod-disruption-budget-maxunavailable.yaml @@ -1,4 +1,4 @@ -apiVersion: policy/v1beta1 +apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: zk-pdb From 6ef4d4614380fbf6721b4f554731091ad40c8c19 Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Tue, 29 Mar 2022 19:54:49 +0800 Subject: [PATCH 089/102] [zh] Update baseline-psp.yaml Signed-off-by: xin.li --- content/zh/examples/policy/baseline-psp.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/content/zh/examples/policy/baseline-psp.yaml b/content/zh/examples/policy/baseline-psp.yaml index 36e440588b..57258bf313 100644 --- a/content/zh/examples/policy/baseline-psp.yaml +++ b/content/zh/examples/policy/baseline-psp.yaml @@ -6,20 +6,16 @@ metadata: # Optional: Allow the default AppArmor profile, requires setting the default. apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default' apparmor.security.beta.kubernetes.io/defaultProfileName: 'runtime/default' - # Optional: Allow the default seccomp profile, requires setting the default. - seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default,runtime/default,unconfined' - seccomp.security.alpha.kubernetes.io/defaultProfileName: 'unconfined' + seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*' spec: privileged: false - # The moby default capability set, defined here: - # https://github.com/moby/moby/blob/0a5cec2833f82a6ad797d70acbf9cbbaf8956017/oci/caps/defaults.go#L6-L19 + # The moby default capability set, minus NET_RAW allowedCapabilities: - 'CHOWN' - 'DAC_OVERRIDE' - 'FSETID' - 'FOWNER' - 'MKNOD' - - 'NET_RAW' - 'SETGID' - 'SETUID' - 'SETFCAP' @@ -36,15 +32,16 @@ spec: - 'projected' - 'secret' - 'downwardAPI' - # Assume that persistentVolumes set up by the cluster admin are safe to use. + # Assume that ephemeral CSI drivers & persistentVolumes set up by the cluster admin are safe to use. + - 'csi' - 'persistentVolumeClaim' + - 'ephemeral' # Allow all other non-hostpath volume types. - 'awsElasticBlockStore' - 'azureDisk' - 'azureFile' - 'cephFS' - 'cinder' - - 'csi' - 'fc' - 'flexVolume' - 'flocker' @@ -67,6 +64,9 @@ spec: runAsUser: rule: 'RunAsAny' seLinux: + # This policy assumes the nodes are using AppArmor rather than SELinux. + # The PSP SELinux API cannot express the SELinux Pod Security Standards, + # so if using SELinux, you must choose a more restrictive default. rule: 'RunAsAny' supplementalGroups: rule: 'RunAsAny' From cde6f321b2d7605b45a1544bf83a906759b3f531 Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Tue, 29 Mar 2022 19:56:50 +0800 Subject: [PATCH 090/102] [zh] Update zookeeper-pod-disruption-budget-minavailable.yaml Signed-off-by: xin.li --- .../policy/zookeeper-pod-disruption-budget-minavailable.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/zh/examples/policy/zookeeper-pod-disruption-budget-minavailable.yaml b/content/zh/examples/policy/zookeeper-pod-disruption-budget-minavailable.yaml index c4776ad4c0..49a66ee669 100644 --- a/content/zh/examples/policy/zookeeper-pod-disruption-budget-minavailable.yaml +++ b/content/zh/examples/policy/zookeeper-pod-disruption-budget-minavailable.yaml @@ -1,4 +1,4 @@ -apiVersion: policy/v1beta1 +apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: zk-pdb From 7580383a7d7f32b010ee9deb860d1061c9b66e99 Mon Sep 17 00:00:00 2001 From: Mitesh Jain <47820816+miteshskj@users.noreply.github.com> Date: Tue, 29 Mar 2022 19:18:46 +0530 Subject: [PATCH 091/102] Reflect the changed behaviour for multiple use of --from-env-file in ConfigMap creation (#32603) * Fix 32392 - Reflect the changed behaviour for multiple from-env-file in configmap creation. * Update content/en/docs/tasks/configure-pod-container/configure-pod-configmap.md updated suggestions. Co-authored-by: Qiming Teng Co-authored-by: Qiming Teng --- .../configure-pod-configmap.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/content/en/docs/tasks/configure-pod-container/configure-pod-configmap.md b/content/en/docs/tasks/configure-pod-container/configure-pod-configmap.md index 8adc4071f4..62b334e068 100644 --- a/content/en/docs/tasks/configure-pod-container/configure-pod-configmap.md +++ b/content/en/docs/tasks/configure-pod-container/configure-pod-configmap.md @@ -218,6 +218,7 @@ Use the option `--from-env-file` to create a ConfigMap from an env-file, for exa # Download the sample files into `configure-pod-container/configmap/` directory wget https://kubernetes.io/examples/configmap/game-env-file.properties -O configure-pod-container/configmap/game-env-file.properties +wget https://kubernetes.io/examples/configmap/ui-env-file.properties -O configure-pod-container/configmap/ui-env-file.properties # The env-file `game-env-file.properties` looks like below cat configure-pod-container/configmap/game-env-file.properties @@ -255,17 +256,10 @@ data: lives: "3" ``` -{{< caution >}} -When passing `--from-env-file` multiple times to create a ConfigMap from multiple data sources, only the last env-file is used. -{{< /caution >}} - -The behavior of passing `--from-env-file` multiple times is demonstrated by: +Starting with Kubernetes v1.23, `kubectl` supports the `--from-env-file` argument to be +specified multiple times to create a ConfigMap from multiple data sources. ```shell -# Download the sample files into `configure-pod-container/configmap/` directory -wget https://kubernetes.io/examples/configmap/ui-env-file.properties -O configure-pod-container/configmap/ui-env-file.properties - -# Create the configmap kubectl create configmap config-multi-env-files \ --from-env-file=configure-pod-container/configmap/game-env-file.properties \ --from-env-file=configure-pod-container/configmap/ui-env-file.properties @@ -288,8 +282,11 @@ metadata: resourceVersion: "810136" uid: 252c4572-eb35-11e7-887b-42010a8002b8 data: + allowed: '"true"' color: purple + enemies: aliens how: fairlyNice + lives: "3" textmode: "true" ``` From 5650e76c450095859725a3231a376693e3ee8edb Mon Sep 17 00:00:00 2001 From: Cezary Czekalski Date: Tue, 29 Mar 2022 19:27:32 +0200 Subject: [PATCH 092/102] Fix typo --- content/en/docs/reference/access-authn-authz/authentication.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/reference/access-authn-authz/authentication.md b/content/en/docs/reference/access-authn-authz/authentication.md index 68e8b89869..bcec107182 100644 --- a/content/en/docs/reference/access-authn-authz/authentication.md +++ b/content/en/docs/reference/access-authn-authz/authentication.md @@ -121,7 +121,7 @@ token,user,uid,"group1,group2,group3" When using bearer token authentication from an http client, the API server expects an `Authorization` header with a value of `Bearer -THETOKEN`. The bearer token must be a character sequence that can be +`. The bearer token must be a character sequence that can be put in an HTTP header value using no more than the encoding and quoting facilities of HTTP. For example: if the bearer token is `31ada4fd-adec-460c-809a-9e56ceb75269` then it would appear in an HTTP From e611a04e6dae76bc8911131f454afe9c39cdcfdc Mon Sep 17 00:00:00 2001 From: Chuck Ha Date: Tue, 29 Mar 2022 12:56:15 -0700 Subject: [PATCH 093/102] Removes a space that breaks a markdown link Signed-off-by: Chuck Ha --- content/en/docs/concepts/storage/projected-volumes.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/content/en/docs/concepts/storage/projected-volumes.md b/content/en/docs/concepts/storage/projected-volumes.md index a498e3b237..ed7c31db14 100644 --- a/content/en/docs/concepts/storage/projected-volumes.md +++ b/content/en/docs/concepts/storage/projected-volumes.md @@ -54,8 +54,7 @@ into a Pod at a specified path. For example: The example Pod has a projected volume containing the injected service account token. Containers in this Pod can use that token to access the Kubernetes API -server, authenticating with the identity of [the pod's ServiceAccount] -(/docs/tasks/configure-pod-container/configure-service-account/). +server, authenticating with the identity of [the pod's ServiceAccount](/docs/tasks/configure-pod-container/configure-service-account/). The `audience` field contains the intended audience of the token. A recipient of the token must identify itself with an identifier specified in the audience of the token, and otherwise should reject the token. This field From 7b7b8d2d5ca901a81e2ce4fb496745651ebf81be Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Tue, 29 Mar 2022 19:51:51 +0800 Subject: [PATCH 094/102] [zh] Update restricted-psp.yaml Signed-off-by: xin.li --- .../zh/examples/policy/restricted-psp.yaml | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/content/zh/examples/policy/restricted-psp.yaml b/content/zh/examples/policy/restricted-psp.yaml index 4db57688b1..99c836b9ff 100644 --- a/content/zh/examples/policy/restricted-psp.yaml +++ b/content/zh/examples/policy/restricted-psp.yaml @@ -5,44 +5,43 @@ metadata: annotations: seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default,runtime/default' apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default' - seccomp.security.alpha.kubernetes.io/defaultProfileName: 'runtime/default' apparmor.security.beta.kubernetes.io/defaultProfileName: 'runtime/default' spec: privileged: false - # Required to prevent escalations to root. + # 防止权限升级到 root allowPrivilegeEscalation: false - # This is redundant with non-root + disallow privilege escalation, - # but we can provide it for defense in depth. requiredDropCapabilities: - ALL - # Allow core volume types. + # 允许的核心卷类型. volumes: - 'configMap' - 'emptyDir' - 'projected' - 'secret' - 'downwardAPI' - # Assume that persistentVolumes set up by the cluster admin are safe to use. + # 假设集群管理员设置的临时 CSI 驱动程序和持久卷可以安全使用 + - 'csi' - 'persistentVolumeClaim' + - 'ephemeral' hostNetwork: false hostIPC: false hostPID: false runAsUser: - # Require the container to run without root privileges. + # 要求容器在没有 root 权限的情况下运行 rule: 'MustRunAsNonRoot' seLinux: - # This policy assumes the nodes are using AppArmor rather than SELinux. + # 此策略假定节点使用 AppArmor 而不是 SELinux rule: 'RunAsAny' supplementalGroups: rule: 'MustRunAs' ranges: - # Forbid adding the root group. + # 禁止添加 root 组 - min: 1 max: 65535 fsGroup: rule: 'MustRunAs' ranges: - # Forbid adding the root group. + # 禁止添加 root 组 - min: 1 max: 65535 readOnlyRootFilesystem: false From 7f782da3b7a50d2197b7ff1df6557446bd732a5d Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Wed, 30 Mar 2022 10:20:55 +0800 Subject: [PATCH 095/102] [zh] Update garbage-collection Signed-off-by: xin.li --- content/zh/docs/concepts/architecture/garbage-collection.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/zh/docs/concepts/architecture/garbage-collection.md b/content/zh/docs/concepts/architecture/garbage-collection.md index a9b6942f52..7fb0eb0d3e 100644 --- a/content/zh/docs/concepts/architecture/garbage-collection.md +++ b/content/zh/docs/concepts/architecture/garbage-collection.md @@ -25,7 +25,7 @@ allows the clean up of resources like the following: * [Objects without owner references](#owners-dependents) * [Unused containers and container images](#containers-images) * [Dynamically provisioned PersistentVolumes with a StorageClass reclaim policy of Delete](/docs/concepts/storage/persistent-volumes/#delete) -* [Stale or expired CertificateSigningRequests (CSRs)](/reference/access-authn-authz/certificate-signing-requests/#request-signing-process) +* [Stale or expired CertificateSigningRequests (CSRs)](/docs/reference/access-authn-authz/certificate-signing-requests/#request-signing-process) * {{}} deleted in the following scenarios: * On a cloud when the cluster uses a [cloud controller manager](/docs/concepts/architecture/cloud-controller/) * On-premises when the cluster uses an addon similar to a cloud controller From 8966e293a0d690163a7bc797d7651d30d9f1c1f8 Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Wed, 30 Mar 2022 11:29:57 +0800 Subject: [PATCH 096/102] [zh]Update manage-resources-containers.md Signed-off-by: xin.li --- .../docs/concepts/configuration/manage-resources-containers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/zh/docs/concepts/configuration/manage-resources-containers.md b/content/zh/docs/concepts/configuration/manage-resources-containers.md index bb15c00543..00c5eba261 100644 --- a/content/zh/docs/concepts/configuration/manage-resources-containers.md +++ b/content/zh/docs/concepts/configuration/manage-resources-containers.md @@ -254,7 +254,7 @@ Mi, Ki. For example, the following represent roughly the same value: ``` From 74449d14596f79da52204683981c16d07b4996ab Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Wed, 30 Mar 2022 12:14:28 +0800 Subject: [PATCH 097/102] [zh] Update projected-volumes.md Signed-off-by: xin.li --- .../docs/concepts/storage/projected-volumes.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/content/zh/docs/concepts/storage/projected-volumes.md b/content/zh/docs/concepts/storage/projected-volumes.md index 15c01c2719..a1cc2a3a72 100644 --- a/content/zh/docs/concepts/storage/projected-volumes.md +++ b/content/zh/docs/concepts/storage/projected-volumes.md @@ -34,7 +34,7 @@ Currently, the following types of volume sources can be projected: * [`secret`](/docs/concepts/storage/volumes/#secret) * [`downwardAPI`](/docs/concepts/storage/volumes/#downwardapi) * [`configMap`](/docs/concepts/storage/volumes/#configmap) -* `serviceAccountToken` +* [`serviceAccountToken`](#serviceaccounttoken) --> ## 介绍 {#introduction} @@ -45,7 +45,7 @@ Currently, the following types of volume sources can be projected: * [`secret`](/zh/docs/concepts/storage/volumes/#secret) * [`downwardAPI`](/zh/docs/concepts/storage/volumes/#downwardapi) * [`configMap`](/zh/docs/concepts/storage/volumes/#configmap) -* `serviceAccountToken` +* [`serviceAccountToken`](#serviceaccounttoken) +## serviceAccountToken 投射卷 {#serviceaccounttoken} 当 `TokenRequestProjection` 特性被启用时,你可以将当前 [服务账号](/zh/docs/reference/access-authn-authz/authentication/#service-account-tokens) 的令牌注入到 Pod 中特定路径下。例如: @@ -97,14 +99,17 @@ into a Pod at a specified path. For example: -示例 Pod 中包含一个投射卷,其中包含注入的服务账号令牌。该令牌可以被 Pod -中的容器用来访问 Kubernetes API 服务器。`audience` 字段包含令牌所针对的受众。 +示例 Pod 中包含一个投射卷,其中包含注入的服务账号令牌。 +此 Pod 中的容器可以使用该令牌访问 Kubernetes API 服务器, 使用 +[pod 的 ServiceAccount](/zh/docs/tasks/configure-pod-container/configure-service-account/) +进行身份验证。`audience` 字段包含令牌所针对的受众。 收到令牌的主体必须使用令牌受众中所指定的某个标识符来标识自身,否则应该拒绝该令牌。 此字段是可选的,默认值为 API 服务器的标识。 From 1905b25b89e132472e4a4ee1ca9ccfd92dd845e9 Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Wed, 30 Mar 2022 12:24:19 +0800 Subject: [PATCH 098/102] [zh] Update authentication.md Signed-off-by: xin.li --- .../zh/docs/reference/access-authn-authz/authentication.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/zh/docs/reference/access-authn-authz/authentication.md b/content/zh/docs/reference/access-authn-authz/authentication.md index eb3b544ca0..2961b2f0ba 100644 --- a/content/zh/docs/reference/access-authn-authz/authentication.md +++ b/content/zh/docs/reference/access-authn-authz/authentication.md @@ -233,7 +233,7 @@ token,user,uid,"group1,group2,group3" When using bearer token authentication from an http client, the API server expects an `Authorization` header with a value of `Bearer -THETOKEN`. The bearer token must be a character sequence that can be +`. The bearer token must be a character sequence that can be put in an HTTP header value using no more than the encoding and quoting facilities of HTTP. For example: if the bearer token is `31ada4fd-adec-460c-809a-9e56ceb75269` then it would appear in an HTTP @@ -242,7 +242,7 @@ header as shown below. #### 在请求中放入持有者令牌 {#putting-a-bearer-token-in-a-request} 当使用持有者令牌来对某 HTTP 客户端执行身份认证时,API 服务器希望看到 -一个名为 `Authorization` 的 HTTP 头,其值格式为 `Bearer THETOKEN`。 +一个名为 `Authorization` 的 HTTP 头,其值格式为 `Bearer `。 持有者令牌必须是一个可以放入 HTTP 头部值字段的字符序列,至多可使用 HTTP 的编码和引用机制。 例如:如果持有者令牌为 `31ada4fd-adec-460c-809a-9e56ceb75269`,则其 From b25f4761a8346617055a9e3dc4ba2b98e5861d80 Mon Sep 17 00:00:00 2001 From: "xin.li" Date: Wed, 30 Mar 2022 12:26:31 +0800 Subject: [PATCH 099/102] [zh] Update kubelet-tls-bootstrapping.md Signed-off-by: xin.li --- .../command-line-tools-reference/kubelet-tls-bootstrapping.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/content/zh/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping.md b/content/zh/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping.md index 132accf337..62aff4d4c2 100644 --- a/content/zh/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping.md +++ b/content/zh/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping.md @@ -273,11 +273,9 @@ of provisioning. 启动引导令牌是一种对 kubelet 进行身份认证的方法,相对简单且容易管理, 且不需要在启动 kube-apiserver 时设置额外的标志。 -启动引导令牌从 Kubernetes 1.12 开始是一种 __Beta__ 功能特性。 + +**作者:** Sergey Kanzhelev (Google), Elana Hashman (Red Hat) + + + +保证 SIG 节点上游代码的可靠性是一项持续的工作,需要许多贡献者在幕后付出大量努力。 +Kubernetes、基础操作系统、容器运行时和测试基础架构的频繁发布,导致了一个复杂的矩阵, +需要关注和稳定的投资来“保持灯火通明”。2020 年 5 月,Kubernetes Node 特殊兴趣小组 +(“SIG Node”)为节点相关代码和测试组织了一个新的持续集成(CI)子项目。自成立以来,SIG Node CI +子项目每周举行一次会议,即使一整个小时通常也不足以完成对所有缺陷、测试相关的 PR 和问题的分类, +并讨论组内所有相关的正在进行的工作。 + + +在过去两年中,我们修复了阻塞合并和阻塞发布的测试,由于减少了测试缺陷,缩短了合并 Kubernetes +贡献者的拉取请求的时间。通过我们的努力,任务通过率由开始时 42% 提高至稳定大于 90% 。我们已经解决了 144 个测试失败问题, +并在 kubernetes/kubernetes 中合并了 176 个拉取请求。 +我们还帮助子项目参与者提升了 Kubernetes 贡献者的等级,新增了 3 名组织成员、6 名评审员和 2 名审批员。 + + + +Node CI 子项目是一个可入门的第一站,帮助新参与者开始使用 SIG Node。对于新贡献者来说, +解决影响较大的缺陷和测试修复的门槛很低,尽管贡献者要攀登整个贡献者阶梯还有很长的路要走: +为该团队培养了两个新的审批人花了一年多的时间。为 Kubernetes 节点及其测试基础设施提供动力的所有 +不同组件的复杂性要求开发人员在很长一段时间内进行持续投资, +以深入了解整个系统,从宏观到微观。 + + +虽然在我们的会议上有几个比较固定的贡献者;但是我们的评审员和审批员仍然很少。 +我们的目标是继续增加贡献者,以确保工作的可持续分配,而不仅仅是少数关键批准者。 + + +SIG 中的子项目如何形成、运行和工作并不总是显而易见的。每一个都是其背后的 SIG 所独有的, +并根据该小组打算支持的项目量身定制。作为一个欢迎了许多第一次 SIG Node 贡献者的团队, +我们想分享过去两年的一些细节和成就,帮助揭开我们内部工作的神秘面纱,并庆祝我们所有专注贡献者的辛勤工作! + + +## 时间线 + + +***2020 年 5 月*** SIG Node CI 组于 2020 年 5 月 11 日成立,超过 +[30 名志愿者](https://docs.google.com/document/d/1fb-ugvgdSVIkkuJ388_nhp2pBTy_4HEVg5848Xy7n5U/edit#bookmark=id.vsb8pqnf4gib) +注册,以改进 SIG Node CI 信号和整体可观测性。 +Victor Pickard 专注于让 [testgrid 可以运行](https://testgrid.k8s.io/sig-node) , +当时 Ning Liao 建议围绕这项工作组建一个小组,并提出 +[最初的小组章程文件](https://docs.google.com/document/d/1yS-XoUl6GjZdjrwxInEZVHhxxLXlTIX2CeWOARmD8tY/edit#heading=h.te6sgum6s8uf) 。 +SIG Node 赞助成立以 Victor 作为子项目负责人的小组。Sergey Kanzhelev 不久后就加入 Victor,担任联合领导人。 + + +在启动会议上,我们讨论了应该首先集中精力修复哪些测试,并讨论了阻塞合并和阻塞发布的测试, +其中许多测试由于基础设施问题或错误的测试代码而失败。 + + +该子项目每周召开一小时的会议,讨论正在进行的工作会谈和分类。 + + +***2020 年 6 月*** Morgan Bauer 、 Karan Goel 和 Jorge Alarcon Ochoa +因其贡献而被公认为 SIG Node CI 小组的评审员,为该子项目的早期阶段提供了重要帮助。 +David Porter 和 Roy Yang 也加入了 SIG 检测失败的 GitHub 测试团队。 + + +***2020 年 8 月*** 所有的阻塞合并和阻塞发布的测试都通过了,伴有一些逻辑问题。 +然而,只有 42% 的 SIG Node 测试作业是绿色的, +因为有许多逻辑错误和失败的测试。 + + +***2020 年 10 月*** Amim Knabben 因对子项目的贡献成为 Kubernetes 组织成员。 + + +***2021 年 1 月*** 随着健全的预提交和关键定期工作的通过,子项目讨论了清理其余定期测试并确保其顺利通过的目标。 + + +Elana Hashman 加入了这个子项目,在 Victor 离开后帮助领导该项目。 + + +***2021 年 2 月*** Artyom Lukianov 因其对子项目的贡献成为 Kubernetes 组织成员。 + + +***2021 年 8 月*** 在 SIG Node 成功运行 [bug scrub](https://groups.google.com/g/kubernetes-dev/c/w2ghO4ihje0/m/VeEql1LJBAAJ) +以清理其累积的缺陷之后,会议的范围扩大到包括缺陷分类以提高整体可靠性, +在问题影响 CI 信号之前预测问题。 + + +子项目负责人 Elana Hashman 和 Sergey Kanzhelev 都被认为是所有节点测试代码的审批人,由 SIG node 和 SIG Testing 支持。 + + +***2021 年 9 月*** 在 Francesco Romani 牵头的 1.22 版本系列测试取得重大进展后, +该子项目设定了一个目标,即在 1.23 发布日期之前让串行任务完全通过。 + + +Mike Miranda 因其对子项目的贡献成为 Kubernetes 组织成员。 + + +***2021 年 11 月*** 在整个 2021 年, SIG Node 没有合并或发布的测试失败。 +过去版本中的许多古怪测试都已从阻止发布的仪表板中删除,因为它们已被完全清理。 + + +Danielle Lancashire 被公认为 SIG Node 子组测试代码的评审员。 + + +最终节点系列测试已完全修复。系列测试由许多中断性和缓慢的测试组成,这些测试往往是碎片化的,很难排除故障。 +到 1.23 版本冻结时,最后一次系列测试已修复,作业顺利通过。 + + +[![宣布系列测试为绿色](serial-tests-green.png)](https://kubernetes.slack.com/archives/C0BP8PW9G/p1638211041322900) + + +1.23 版本在测试质量和 CI 信号方面得到了特别的关注。SIG Node CI 子项目很自豪能够为这样一个高质量的发布做出贡献, +部分原因是我们在识别和修复节点内外的碎片方面所做的努力。 + + +[![Slack 大声宣布发布的版本大多是绿色的](release-mostly-green.png)](https://kubernetes.slack.com/archives/C92G08FGD/p1637175755023200) + + +***2021 年 12 月*** 在 1.23 版本发布时,估计有 90% 的测试工作通过了测试(2020 年 8 月为 42%)。 + + +Dockershim 代码已从 Kubernetes 中删除。这影响了 SIG Node 近一半的测试作业, +SIG Node CI 子项目反应迅速,并重新确定了所有测试的目标。 +SIG Node 是第一个完成 dockershim 外测试迁移的 SIG ,为其他受影响的 SIG 提供了示例。 +绝大多数新工作在引入时都已通过,无需进一步修复。 +从 Kubernetes 中[将 dockershim 除名的工作](https://k8s.io/dockershim) 正在进行中。 +随着我们发现 dockershim 对 dockershim 的依赖性越来越大,dockershim 的删除仍然存在一些问题, +但我们计划在 1.24 版本之前确保所有测试任务稳定。 + + +## 统计数据 + + +我们过去几个月的定期会议与会者和子项目参与者: + +- Aditi Sharma +- Artyom Lukianov +- Arnaud Meukam +- Danielle Lancashire +- David Porter +- Davanum Srinivas +- Elana Hashman +- Francesco Romani +- Matthias Bertschy +- Mike Miranda +- Paco Xu +- Peter Hunt +- Ruiwen Zhao +- Ryan Phillips +- Sergey Kanzhelev +- Skyler Clark +- Swati Sehgal +- Wenjun Wu + + +[kubernetes/test-infra](https://github.com/kubernetes/test-infra/) 源代码存储库包含测试定义。该存储库中的节点 PR 数: +- 2020 年 PR(自 5 月起):[183](https://github.com/kubernetes/test-infra/pulls?q=is%3Apr+is%3Aclosed+label%3Asig%2Fnode+created%3A2020-05-01..2020-12-31+-author%3Ak8s-infra-ci-robot+) +- 2021 年 PR:[264](https://github.com/kubernetes/test-infra/pulls?q=is%3Apr+is%3Aclosed+label%3Asig%2Fnode+created%3A2021-01-01..2021-12-31+-author%3Ak8s-infra-ci-robot+) + + + +CI 委员会上的问题和 PRs 分类(包括子组范围之外的分类): + +- 2020 年(自 5 月起):[132](https://github.com/issues?q=project%3Akubernetes%2F43+created%3A2020-05-01..2020-12-31) +- 2021 年:[532](https://github.com/issues?q=project%3Akubernetes%2F43+created%3A2021-01-01..2021-12-31+) + + +## 未来 + + + +只是“保持灯亮”是一项大胆的任务,我们致力于改善这种体验。 +我们正在努力简化 SIG Node 的分类和审查流程。 + +具体来说,我们正在致力于更好的测试组织、命名和跟踪: + + + +- https://github.com/kubernetes/enhancements/pull/3042 +- https://github.com/kubernetes/test-infra/issues/24641 +- [Kubernetes SIG Node CI 测试网格跟踪器](https://docs.google.com/spreadsheets/d/1IwONkeXSc2SG_EQMYGRSkfiSWNk8yWLpVhPm-LOTbGM/edit#gid=0) + + +我们还在改进测试的可调试性和去剥落方面不断取得进展。 + +如果你对此感兴趣,我们很乐意您能加入我们! +在调试测试失败中有很多东西需要学习,它将帮助你熟悉 SIG Node 维护的代码。 + + + +你可以在 [SIG Node](https://github.com/kubernetes/community/tree/master/sig-node) 页面上找到有关该组的信息。 +我们在我们的维护者轨道会议上提供组更新,例如: +[KubeCon + CloudNativeCon Europe 2021](https://kccnceu2021.sched.com/event/iE8E/kubernetes-sig-node-intro-and-deep-dive-elana-hashman-red-hat-sergey-kanzhelev-google) 和 +[KubeCon + CloudNative North America 2021](https://kccncna2021.sched.com/event/lV9D/kubenetes-sig-node-intro-and-deep-dive-elana-hashman-derek-carr-red-hat-sergey-kanzhelev-dawn-chen-google?iframe=no&w=100%&sidebar=yes&bg=no)。 +加入我们的使命,保持 kubelet 和其他 SIG Node 组件的可靠性,确保顺顺利利发布! diff --git a/content/zh/blog/_posts/2022-02-16-sig-node-ci-subproject-celebrates/release-mostly-green.png b/content/zh/blog/_posts/2022-02-16-sig-node-ci-subproject-celebrates/release-mostly-green.png new file mode 100644 index 0000000000000000000000000000000000000000..c88eb3b37ef7c44cfd7451265799e7186f40e8a1 GIT binary patch literal 101346 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

?d;dkwb|xhe)j7$ zJ9RZXAIZ2VN=U%$dhx@`e&;MY7i_^mJFQQ!)n9A(HpMWqR{u@e3kiX{It8XL`8*y_ z|H#X;uNqQJ7gSydQT;pnKzWXXQOE_}=kAWKzLn3->JY@vM69)7W4mI+GLy<01LLb=)- zmz7%gY^WG z?%5&#$#iu2Y5@$54r6lrw{&yv#}D@pdSHNFWw)a--Y150XAoeuHP&)ksywf5v0EOg z@=I@yHxi$NwInn&)O?{juj;4Q-HNM;pKn1sal2-=pFC@NXHda|bavvR%i zCufa+_WZS2;WiwuR$47pzIT>q0Y6Rk$Qvxk#_-QWWW{99^mE zkKx6G{gXl~c?hB+7~+q$pfZWo)ZFxhUiXcDXhBF7bax=QZIcL;Jh>acO@-1Vm*3ndgC8Vj8RO%?C_s;#=_+!)kM$>xLBwA0rY{9Y(Ns9x-GGLystC&xUE3H{`Q3=@mN&# z)qUUd)JDB&7}lSrH!Di;r$8eVcsuwxkYQ`>*9UtpbzSinMql12M>dNo3UbS2l(7gJ zQ!9HuM$Q#uI(U@LyD`2qKk%O*-XeESZtgJGmdlDx$Fl0L$bU_T1k_<<<9kQfX*`C^ zItUwr&!SsF7BmdpBz>V=`mRF=_w~GA6IYnT#CoP0vFUXO8pAJ7DoH+J49h~b(pAE# z+!0UnI*z_!J$j08-^ZL(zoiO{A6JBnnGOANa z_t9{^`4cgKw(QQeNZ~dNu2ygkEF|j9{24Lf=Y*FssgBQ3I5tZEOm~or!?mDTo@LIs zA=+C0Nfx?SZ)WZLZAtn4f%_l75H#${5?Q*MKnBtXi|p{jitnV~M4B<*?HIY0zAE4N zb^WVGE&eF7q5a#G$wN4Q2Dz;1YY->@9c_|N1s&A- zMI~z^{dY$|UY#T8Jk;ScwmIxSO3?T(QelYPB z**YnuCB?sO0|-+{18KqA0loOI5}&d-e=95deKGN02UvdZw-yhK6Da?&?CAUuIUid#aWAi4k!9;I z#!r8)7n>c4mz(TuZ+yMIQ>_C440dQ@VgP6*$8UcBc4IK=Bq%R0FMTrZ3+q`~!T0v| z{vaGrz#C*So@ES0%m=nC;tp7eU zGt+A;l6vFl$TnmOfDkV>!-=y@*Zgk{RPJ)T_cBYz`@&I(XVV=1ckz{wA&K-}T~X&i z84l{DqM#_2!vhQ=UcaZM(SUxUw^xi@n@TCiYE?%d11syS^8p!K-zm`Ac4sINhvma3 zohAlm%RK)k9nV|K!gJBBXkLLGwPwy(4rZ0>C zCkiOzhxBXG`U1cQz$FR=x`u5?-DZbeG}MOAPWLJ5N~~l9jZle+i4*q2!^5>JCxg&X zvvQ`Gx*w`QgoLpvDHyhMC;SFV4X7QDm!lI;4X~IP7#~(!oHKY`OPzJ5f4T#+Uhm)+ zi*!SS{E6hFp#R;;)X+9JA)bdO04gDJ8)rV9f0v)I;d6WX)4+!4yNs%Yv+LD3H#rZ_ z-6H&MQ>|iKJsrJWGPADDNIH{2+eRq1;T!cq+7WGlnbGLXs{Rkg^q&Pl4FM5v>VO0G zT{2JSH9`c%MMkn7X|$HpShaba*gz%_B8T@3vAXDgWp`7rW8ujN?Dv1T;XJ~8I$ZDS z!hH#w$H!``=dxcmOJjtXuQuREUoXPdgo%Fsceis=1D!9rxVCdRv~0q>4iK-5uN@bD zVPT=u)Aa&>b_t31PNH4Xh`Y*s4D+6IXPW|%GgI^LmSvO#hlfaK32wFo{bIB8Cel-$^V~cxuBQ1 zj>hu06a20L?uIg!13RMFly zD*k_$pu`e>XrxB;J*)bN0I=hSqYUnu77ta znm|5sCw+8FzGKQ6XJ#+&^f?(y5B_6GN;Z1#no;D;ZHP6ej2AfqLz*<~cK;8iZ>7=N zcfGRPc?7+kBgHMwVC0UG7fbxVH)xnlY{$m@W&mgt!m1~mY67U=yzVU3t%qE0053)T zUrEpex8vOvip3i%n1{5mnrI93l>ulX78G zQ;Q>GrbYlv;IQ!L;sBfL0uPUhiy6Ez1seh*J#t~!=MbV0NsyP99{juSK}9Nd9M>CCTzlFrMHNXW$BGm* z4(#nCymXW7M0vrX6`-TyM07%hleNh*T%+2V+|q(XlQY|iBjMhuXsZMj7LxH=vPSLt z57??-JXSg`;Jg65G|O%YEr4?hrZF0Y1w3vOYd5*!0uWy0A$#dUi=f~?7yz)C%X|US zB71C%YzH%nQVLq$Dgpb^uU%B{oq+~2njmVkT7ecRGVxlh!3sAiwII@kbW$SKnJSX$ zhbuHz3e6lcG_ii`P*_BGsXA>RHnrKQb{+KNd;iKMEDQoW{r5}daEsTYw?jO5%qQ4= zO#4h&>1j1JDDyQ2I`kB?JF5(UbFXpcGuQt_TaVY!0$AMdW-b#`3>d;NjU*nhNf%dO z@@DdJ(TLv4$Sp=U;&*~P-}B)~aC{m!7Ef!*PfAjEq9MgaL)#n(?f1%hQ@0Aev)?;v zfewjG5xp`Zy(;$L`4l&xXxguc8B|qFF2h@EgebN~gK_d+MNNXz{FkMr#R7aQ_qq@I zXgc#?1RA+bNk zA8-3xxXwLa<#$V&Y0>SFb<1~9xE_&RXbXw)0@xj3o8;uIkozl3lgYq!R3f6VG8i2Y zjef|^kM|T{>PY-ilwlJ>YYMEKs$)B^Xd3v-Tgk}uW^G$YaHYAlhoKNCS#7FTmE7%k z6)u!_3kKabp(`LCd{vB}o(6q|6R1vOS)(*OGSWMn{CNNvV5jm$p#TS8Dz66&UZJT%k|falJ@22`lG;E>VvK}bzq&3UuZ zs_N?BEC5ODv>G3=1>uL^>~6|Ur$=~*SXv$4iGr1= z03<*_fJ)QTOJ?PAMfq7uU-6@8gzYQ=AwP`C;8~aH!wuoV6caKl<1!f&FJ>lL#A3Ap zICgwt6q-QmZ9i$?gqHrtx4@dw6$WTL#B19|emW8{Zh-egWu zPmhXpEwZ%fTrS|=dPZUCUtXDuIVNyo6GJl6={NS%U-T@!qE~FwTfVxK7_e>+1=s!v zRa=q_`1XiTZg)qL%k4J>t>b?kV; z0%Rm%0NIco{#>C^8PlTE;nR3HP!ul|RfiqNX%aY}TOkLuirwiNG!$fHh=`Bph71xrD$RBjizgC%?URAddV8uzTq;Bb^{2;!z13nZsYNIM zYy`hW^sd=Hj_B_pu=IJ?%M*%TvxB6cm_X;<7J|UtM(|#HcC+2UpX(#hQS5&7BQ^c! zhyDO^J}TW)#W3gH>$COsC1v zulB}E#q7RmliRg`h?ty(=V;R03&g{bCzb)fd=F4sS`(#uDMrr6v^8JjasFxaa@$&%8_Dr;y3)K0d$w@>}3-G!}C& zeNDSbmEf`Zx4rQg$%x)k&zd!!+jdv;sv?tD>$Y~i8Qg2Iz(VO?JW8bGbw}ztHo*6;T^(mmcGIoH)}@nRcCjWTQ|1i zX3-w#rWh0wuDYc3%IImx|8kdA+Bgxw3M#}&)1>D;FUeS0- zBW5;Dg41|=yism-FM^-yn3$gK{GNx11N-ee+>bBbXSb1*c!WQB;x*Ghkpj;pY}Fi^vZe!*F)L>y;u-!w4|SE{1cW}JtO+`K@MYHniO@VuizmVJ1joS@*R7AG1SuRZOCkl?Zln}zWdcTi%A zlBB?#>DQ37UMp-ZcRueH-8MANiAeop&|kp0Oo)$ftFP%cCvbCM3epx_hsM^DUS$#5 z-KAwNGV1z>!)IsJIB5%`++g!!EK+dpjLG1pu0b&r12@6fS#dk#gulJ!b9%oY6CI;j z(D87CHyZEGBe~q5^#%7x30UkgsbOh?X+Sc>t2&D_nEK{uebSn;{tqy&nX1=l3n8qQ z{yP|oD84evY-S;wCtYXVZF9B>UI#2$9F7cuy~Z*;NoE5j)@v*TYnM(V!;@^Rysf8L%5YnG*g3^v z5E-PJz*$q*m^6o*hA#S@u*EZx_;g)%7Nm+kHc2f5@GQTARQEO?ft9QAQ3dICCY8>Cry{{5RmpX-zj9r|hV z-HY`v)kT$@zk+oYbV#-@=B+YQHbjE^*TajXv{TYI$7wwe1h5g-kY_Nlb$-_{cPj`} zR5K{fu|<-L&?HUHh-AG%WAEYKZkYrjf~B_=o$C~0XuB3qObTd{!VN7nxuPgAb5;l_ zxxo8-n;#4#!8T?EqVJ(N>{eA~;`&%mm+`0As$=UIoCt&sMYXkM8hwhZwBTvIL`jce#Cj`>j zIwVwvVRVxm)&?iq2|fvC^YZ)(Vz!mgq~G{YGf&}852Yq{02(V9mt7~B2PB2*2t91M zHQO^BRLE}6P*pjZUVbKRy9!Z@o5qf;-{ica@aUl!MFN-Rs&>DNe(Qur{m8q$NDM9k z&QJ(O$$)UNKs9vZKA{D(nW?A{q?OH9gHWXA>B6hI-Wr7_jKKrr+6(h^!#xbHD)rgt zOPv4sv|eFHhSzH778yu8kqmJQrcR;Xp4b`X;gFuGuhU}-&Wc7DSrC51e?tf!FbYV9 zc#N7R5rB>DZvzn$P<*B*W~auGj1+&4_>rhh;QT)Ffs%v*)f*(AobEWNic5Iw)Hx_>f zsJZn6p_~-L3WOE~J1`wVG@MAXY!^8yJIVOzfMPfaUM#|lH8gxUqWPl`+kOg)8VW&@ z=!;pcFm4BrmIc|DZa74^WYsVz1^uve?N0)~t8(4AuU=-~hK{b9JSzW-r35YmVHGX3 zzu`mz6_OKlX-sE|EoGyUBeIJzz!AHY3Wme9Y}$DSL7^Q_l#==k3~Wzg1ra!HB^hD4 zjMnS#K*@q9k#J#qj2esr-{GHN35;*hT`qp; zN{iZLSlLbEcq14POFVR<-JxVLY;3cM8BP+==` zoB04^CmXZsN05nLlUURkrHJQRkmlv zK(Ft9=I>3(t#@(|<>vo4snbBb+N+>tKR5+Khb%(|8zVT7;Hvb)UV_kLI#l-jL4oAK zclJwl2;RIpRy3z2En(AEAlh&K+~}$lP-l`uJe>AfoNTNdxS7^gSVVybd#p*IQ^p=} zKU-8?j1|K?!2m+|XsenTK6}w6IF|Fn1_?)k9fht(#`1XjKa%tRKtKt=9ua1mSbO&t z26F4;CCC{4D36hq6FEdy*K>9VH6;9ZQoa#xb7>iB=+a??_2QdY6TN(qEqgr4A%zV# zLh%eo`Qs$-u%wx!%wPub%kVRa{{ zUOEcg1bvb})%G+G{!ilB>vk?jVX#6)J_!>h-OF525W{09?IcQPCwb4d(meK-Qs;f9 zPAiC6on)2;Bj3J~3N;w1UR^DLnUx0#+_AH76cUo;<`!>DimN`IgmoG_1cL^fh8C;N zUQfwiq0*ohX{Lc$pz|IYsMM@h=OWOf;AjP?FD(VN1@8X`pv;GU%{>!0?rAN=;dZ6r zB;-QFZ_0thp!_ltl7fs8p+Thq8F)pZL`5@&B0ujSv3)?p;fO;k+D8`i=r>*G%>YVb z8*7jKiYH0RBT{OWaF?q;T+c^$f{i(nf{2WZF1=R-PctS}3r*rFXkVsqu|a=DjEOgj z@@|)&-MM&8>o1I$Z-{=*qZfs%ND#;+A|aRGHFgCcMngkRvKJGBr@`;)*oEMH(c_|Q zW!1U~*M{nRO`D++Ut0E2g>-J&*X{vUOZWvJ{Kb6h!HZvb(#i&Tl}SFyL4HSccCQAO8<-A283mXAUGV?W@@DHh^JBUY(ZKz>PK6_S zlH9;p^iQCqU5>1GjE`}3RoROgF|mt@kwvG3==ae3r0so)1|kSMwa+4N5iKJ?Kv#FA zp~dVX76=i%h+HI}<))Au@eGVH+TLe|lq z^u@NU&}s1nkeg!CN~_0}54Yr|KR1 zhOiGJL6`tMKJHnVGZ%6lY@O51am5H_x_%J$=Ku&-;ml|~ht?8>Ysb#}fiWfjYYnaR zB|~iboX;C8nCtWX<<~j?BFReduX`ee?0Q<{cS=3FZiP4*TX?hLO%vkC@Wfq`7ZK=( zccy0r?+JJ^g3d+IxRPeZWjQ)1WENKj12NEq`;qaHM~4Q6t*x!FS45x_74}KU7oqP$ zyRp>x^jZvHnj)>y!>LZ%$h21V*SK&Cv`gL3x5lOmT`Jh8O(i6tC%QKL{5T%S0hIKG zg^BYBdE(iLONn@L5 zOb}67)49AvJ(2Jeuo@u}(p^ZZ)z{abuZ`W-+COlCB?dQMT>t=1k@N8XWoG&v{|}}g z_y<_+%@~X{ZUuL;8!QIWLTne5H-Jr# zsrm+J4gnb9)k3siHMyAcg<3EcU~^D%=Gr8$u%r&!ujln9`1CV?c&toyc^EDRON~NU z@8{P2*y}RcWGbuGmOAVB{l<~U$$it6d3y^^0~ij0qpEMUF1vC-NT7s;m}3w%QGnRM z!?1Y8*n)d$aevLrM?t9^R!CM>RvbYa4nT}%&1t^IxzUD*Z17)(DKI(b)xQ!z98d=i zA>(6%>|bMJ4D!TcGb?p^!KpJm{uwI<$8&>@t)XD`sih1u#$%X%C?rqYlc&L{#Y{zV zFl3kmeu*v9f(4`=FJ}idM=}JlT`g5SB1WAGRfmkHU#t5jBxad9HYmlS>cf&PT?}cR zKSfH0y2{H2&(XYUp7tklU$wcEC4LFKCKH3MF}`*`%2cU{!t1yvl|Ev*nby@Bo*8yH zPYT}VOGaZ^=mC*)d(0VU4STP?wCziujh=U?WDd>b(s3UEO0qPLH-D9Qpx5v5Vo-{} z8GHK^*2mU!98cWaj^{r|RQSh5@xmYo9iQ)3-X;a1gH%{R#$LxhhN`s*1Tbu5!O2(< zU_|G2<#{jsGqwX16%<5#zv5A;;&hWaI~`H zv4jSVxd7ytOs$Fg-HggRa-)DhI*CG0UtVX+q#(6)N=ZJ3+vTdCikzJ2o!p~R1o!~V z6_?t*MUtt~uDzF-M2ju4%JM0*q^#x5A%OV*WV1NN5x5#-zuQSxo~pLzrx-dI(j;M( zHrTr#TxaQw$;kg;z0&mc3ZrUU7YEu82%j?r@O~#CiP7Zdc!_F$pi#+uRH3}aDrMIW zm!1Xy2v0T<$4*z8nXB7>jj%o7mW_+0guJs#T))%p+;uu|e#GFex{bu>&oX;bbCj>+`lB^7oe%7&Rx1C!}B zadgcj?s$p?vy0dEOr*D5%uq$*zNypTYA8S{Po`KCSLod3 zf9cNT_hedbc65XcTWPR2jdNJ2&dvN1m6io~-n72;&)5)!TKEDdC5GH-8TwZHu7@V28q(fy( zE5GJy_NJ5k;+@lnGo@p}7UGYIsxp|Qt{j4T77)tmw3y%|@+GCWCjPR?)_8FvopzZ> z0@BNy90>Ci8EYnUoB5xnNsZY~#9*-)?+7M^?s14(&xr2sp-1lh6n+NzW$uYiERm44 z!w7~CD->p1-`DR>h?sCq0oHo-c7DL>u-FyQRaeUL#tZQ4%$%*tP4+01zXl6J;~Dvn z&zUm_rxI!RE9u5+))?9|C=$enU+^YVE5ks=QUjvVS49U9s`qBwYjF@o_zo4YS&THa z*)A~Yd!D#&eE-`d|HtFCm&Sj_qE2%c1-qH=I_AZfln`NtyhdI9`8^uDH;6r%k(6T? zw^c@N9E>)6%A1rHXO@Y`u6pxj$Tv*e0A6CliA99j+4w#(n_gv=76~kdzCxlMDyiq_Lf2m$Jcj zeIf?53b+IGo$oPAiMGuu=wkYfb@>d`8#Vsip2Y(xhHyZ(Cvw9NL?Qug3sYv6>eA|; zZCkmXYdtHDU9oY1eY6sGg1Pe!^6R#4_AL8znCWY-;FqShqLY6a*t-?<^Ca!~UnO|0 ztto(bb@Te=8N1S4KV$4SqUl$e(J_vmP6c5H+Vb_UCivU6+Q=FG+eh?uTw4xo7hE8A zbqZYNF^@u(3s546=9GqbI1V1^x8xTrMKns$<}U_ra9c1r!Rrf*{iDpCpBg^l0C|RQ zahz{>EgUK}zh;rvho#|jr@M?%=_Y23jOUxS{j5;W5OYXQxuaDtegDNL_Gn61yg4hC zb9ecTscTC|JM6YcY^yV6$$$KnK+1DHIuDbxYkgn&@HL^3AI=vfp>b^`E7kuKZ}9^O zBL1hE`|QuIGo9O$pYP&ai+cCYeB&D|{{dcwVas+)KdxGK$o<=rUx$6tb@(;@bsphg zErbg2q?U5xTb&xUe-?^J2Pq)0T3fa0Q2G03!GLb+k8|EN-M>u#5BygF!vF7I=#Jpl zoUiz8=iMMe?dT{e0;R`0yEVgAXy$LDO#B2+DT|xCyKldX&zlECwwuu(UtV5Zru}ir z5s#yzJ;B2!TvH21lD$ZKD%EhfGu1mJdaC>@g`o!@89 z0NPNW7A~FbT_82G)xJhMgdjS8GOw(4oYW>3^8ct_RK7z$`)$qF8nh+dbtU4Z%_L&# zYPU@4=_}+P$yRZNzP*=`i5pZFcIdWr74EMl{GO1W9Ub&yddB~zsAA?!*&<1{Cge>4 zHfFinG1&)EQ4D^p_wP}^2aGN+=J_u)HaF&z{i;}WVzhmSAXjHBih9V2IwPZO!N&e_ zwmOVYZEV4oNkVeZq_EfNyUuvl&V819+j!(A=B8CU8Z0a+qxjPK#Bw}k%yV38e6acz zfglpDbb?HULbeGf@%Z@DdtF_4Zc5pt3`cAD`E`KZWBqlY%JY1;?Y#bUn@Ji4AMJFv z89vHN6lSfgY1`;jR7Gk0{p-uMdfTY7KT_Z@=5Cxd!`;OXedQ4>8I50^ux92 zxW(F=%nNUi#aGqZ4jJ7AMaE5$ka9baN=U9mscNf*omfC!HG6LX(d`r!#EXeb(DTadH8p$MvmhD6#Js?R_! z>>xle#$X(Of?2Imfi!Y z(XjwaxH(81z+pZbU=+8ys{i|N<=sV`ms#U*FQEMEosSoEunT@(^Se@Pzxicb`oinF zw~>;p%zEEG?!A{y5pFI`=#TLluBeXnYw}g}-h0Ko(J-sbey0@R!AGU|Ii$02WF_

nKav7Ouu=@aVfL!Nc-=nmVlK|bU0W5zfj?ZZLbvn7})+AJgO7SS*f)( zzF^e1B`MrZ3IiS%!vLwNp^<~Kv$F7bb|DTyYT}g`AHPc|N;p<(H>3Awb8XDtu1RLc zxW({abMUCm#3IE7jQuINH&-OjFB@hUG-|L)T&mHv3$#M?8@OXvp}$%UczLSxxwc98 zG{v+B^mGpOoz4N?*_XA7$I%%yC3N)k?DzF*>&=xDTAJzxrXzh%I>1~x@!5$B1`+3j z$4c!-sE>axzMKpp?Gq6bJH`dlwS&PDpb6wnBvtr4^nOzj2Goklx&{jB5C*wy79(ef$X|{tiX- zw!=3XNh#_#0aEH_d+!&(Df@|HA27rBk7-#3t!yh3$0HN+;rM1|vRj6IHEMLx2!=TA zI5RYDcmzBVn~SFL*DI^~-u@eKSA{doWjtO=ZNfBx6>(CV&Z~c|e?m zE)E91BeIH^>q8Ml^vU_@JK1qSQ_&01&e>NSC*{^OOPWD|&Ua zdVKU#X!U{zTG+EZreV~TR>?N4+Qv7*FepF{GCJaP0Y|J^?SzIUtTB-AF}`|mc+)QP z=G%&y>39|=j-U_60Fm(g`WK6TDhmb#LLgQWzQ;B>zK}_uy()Jkbg3Ls$Y}ag*vO?C zMHF4RxE$M`$Wiy(iQGgcZ#;t8abG=iUM_4blCD}DN|R_cRUJkY!N|~UOj9FL(a@s> zlQqk4i9fmC*(XW#q7K=|5RD1HMJ96pwO-R@El)dK#cjDcyOft@KN?+8{-^AngN3-z zVt~;N{{)b7k|TUN)VA%8|scTlJMv zqPgeJvbl`s9Oc3O0x0%itV&l@}`4Q7^>+4bGRabDr1Tnt4i1DAaG4eKQB=UWJi z6#EW~wZ>Ki(h;UJrI8g~K|zodRFpx#+JFo<_|~s1FbfnM6w2k+AhsgZKCnzaAPZHcQfYR2+KA}~WtWV}$!N40!d;;0EB zQh0xK-gAFWjuJeBAoR()ulL7$|CZ^pkJdR1+`k8Q3z}r@h`fKJy+&>WN-=~+z2Hlc z$jHgyaV^C;%;As{xDE;jQ7VQXOSIz{~$pv?1gZ z^dUuHCvBt7pfh`id#U#KdnJ%M{?6SA+(%3LrqiCS5Ms)f_h)DFo?TP%sw=mVjJ8l$ z;W&WGfCsJ*g*eXtW^E99uSif<{kli$m}G{gG+yX&2#0bOtDi2L-?N&w2wYs=;Qb9X zTbif`5XHPUV>okYaApmW4m*I#pZgb4TLtqUW7Xv9T@SdjA(Ys(Y`pBG&wxNJ29I+@ zCKL~!EZ}Kw0Y|`#MG40-4+# zfSD^*dja}`*EXTS2f8qA^&Da!4YWnh&ieb9YiEGGSmJY*Q<|1c$2;d5E42&@*bGA8Lp8( zAMbTU6wPG!jq~Ptxx8W?&ap8+roR^9Wm6%(4m7pyjwny%7Cdo7RxX$MF`JQ!J!p@g}$!*JR z8+9uT_@{X53PQ48*2cu)MfB82!-myd5bq2SZcF7tpFUWhYPC50TK|yD{bVSH7l!gH z8rj4vi^k?N4_wIWy+oh%rs8YMd`h&T+I6%IUZZ*rq0$9fjmHY>{=N~b)lMQ#z^0k1 zZ6ve|QG-JwFRlx@+0dRTFC$;(g1#%#YmCLJ&(T*YLNTph_>L`THJyLxm^$xFFt9Mg zzM^1{#jVM@c_P0rnktH98czv3u8`nF*~j3iDc#$`pvBXWQlvE0TwPE*;#|v<2&<59 z%hfxKU07$SDBmOx%P!=sT-Zp>toZ==4d1I4u91CZ&%mV_pUez)-j zz7&A)ypFmYHvwQBUQZd@R*_Ns!&fj~AtN#rU6PaP6ZlRDC@Ho&gUh=A?c4J;NKqSg zNAf95@QE7}8Iuzaz+@L?i@LCm&a`coW(C@if86cXu`WOx%G;DZc?BEL!@MjnpP+mvxQUpMtHnR$oG>8KgwkBrL2UR2A+ zcv*X8eNH1aWGxR{eJ{J3Ea&|0ro}cPCo3`}rb$LlF;TgKC*>i{gGE||%nVi|c-wj! zW*AYpKu!I+VA z2Y(%MjhB4CTrPgkg`(m#(^P`Y0>_x3{umo*KqOU!PPN!b25n2Y_$4h)@g&$O zi`c7uy@+#(LTEAQy`Tn1sMdMm>{~QTrlI0qV26tjDHc}I&WW~LZpDt)#+cy5<Soak92G@3Kt*~Fex~B&L|W2WlEExj%<)ol zKbc2zp83L)aDqEjsUzlj+GLX^a2IF`pj-qjfMvGAi@{ni25dObJ@y3{qI zm~tXJY7uM}$;a?n4Kz5Qp>C?_UrkfVp&He(bu&)lKvdm9@mYiDUW=SiGn!kY={Gig z^@c~JW=?9R`POF{eN)_cC^>l4g}ZvSFaPIFfqJZ(j4!A7n1tR-gBUzYqEg$t$l-26 za$JE{NN)byr2=b9ZMRC)dWq|Os#a7_Ew}@X>^+^W%2L0iKwl~qT4b)pTbt%8*wdsp zKA9(`iDZQ8l)I@yf)w0g8+V;N$8j=Erw8gT-$h*sC$0G*_ z+Ni%;+ryqOm#48{wo7Zz{Q3z8_5AEjyqJ3i(LTuL;$2p@`yGC=^z=nPAii#*O47G) zoc$cfyUK3VweU9AsqBf@J*811)hv~|t_BSs{}Sm}(OqI=aZ6Ye^zU@OcNI-@-L$9c zOv;T68MMCgA3BS*;YN)#5iJ!{BP>je<(0%rp#Q9B=fnruQlFsBrw%9i;Q!_PCAf)IZ6-dT~Jyg#wV3cc@{xb_8NnrnUcgec(AnSdHChZExE ztl}jc&QjUxP5(P$zfY!8guxv?C+1jU_9{zbNYOG}-*kq4-gn1%yiG~SJuQrS4feO_ zSqcgYA{2rWqL3mKghv6g5s}aMwZmg4uN>tA`Z_yq`?EN0gHDK4b+(0UC6WZ6e_znh zF+`R5Zz#pqWba!F#2berA*`A=j~W3Wcgth_sOLy~mMbHd`^)~aZ%x;Y&y+Ve5%oC^ zu5<3f7yzFIHO=)3V*|?z2_KI!CE#PBZbkan+Oqk>p1nsg44J7;-D+|QIvTwy@gEu& zLqlT;H2tad?V_>HS4x;c$qYTuChbHiBamr@kz#goFf;u~?GK$#p*)elMq(_GsQ8@% zm1rryv4#u+_?2d?$o9J-AQ&qgNa+PL{N~;N#_RQv+pHIYGCT{!G%gehLE;np3>6Gb zPNFdU8QmNAF?O$yiIU;O($*kw>V|0V`Qd2g;trLC~6yD0^=*H{_`8 z;N_9n0E7WMH8B()%D5L6x8s#Z)}MNcF;tAS)1;@i2s&WTggh2E*oJ@hzY%vxH#~R3 zg(*tf5}iZGZ(UMF*~1jXF+IL3!#d(@w16fG*t&oTpVR<KrMH){L}QFK3|(o?vF zkaipO%-x-sO$;1Z*|6Z^IGkb2hm&x)SKyn-G%2_)<*3$FWo4|BgL!mB`8{j=r(Qk< zZ^$SIuQ2(4^DPQU8n94s(5oj`9}cRu2C{Ix0RE_!*OC1usb7HlvoKl#R(lR`ww%zP zbMkL^Uh6{s&THT+v&aaHD;A&go_FJY^?>}{qW$`4VH?l@a8zo!5|AKdr6BLYLbBly%8MmV3px?EOP)*XY(Uc0kE`Dz7I zA`ajKcrz&5_E(0Kx$~T?^WmA_?Qr#Ny1~axov1z=Wjn)wC-*A7E@U815Ct#_nau;I z4Ywv7z8-vKPj(1!FHcUV-urkRcK}FGP}PpOpBErx(aDAm_<1=hYlH!!Qd9kEoU^a~ zoByalN_zTs=)O_+%z9ek*AOzE`;=r>r;ToyhbynwXfNaIthu|#Z51EJ@tadkBC zIp%+7qUL@0C=PJ(TpL3+cJ% z&3sj}imq-{k2s9!S;tM-xI-U+Pdq(nXFi;MpVW7KWYk_jleMiqnzxx&>$5#p>_< zTCWQefybe~fsYjW#G9w~ow#Ao_{W|mXkAVV=C!uD(M0bIqYEY!50*lz3pnlq&Yn;f z3_Te&tM!*Y}B?q8N@FNwQ4U}X|g6|q{D4d^4ADXLvGlIdCAna@jlDJf5zxEa{`Aj`G)f+Gc zc+@0Y$Kbp1OCq_1Pco8n6*Nr4gC_pISIX=ig_OyTX|a^a{8%9si1@>{63)AH@Z9EG z@k>;>_z~i(xBEt)#>N!RA#P?ynQ^m`);`IGSp@Lm13vBQ0EwHcOL^w)OMajVb200>}d z^wyS%sZk&C!YkZ|7+LO!lFrn=AtvxJ_6>*UL%w&5;Y;%olJkdbP$cZr4!SblPhsLt zC>X@77_fMq`(+J4O0bWGfNGbq&J9xcg)%1|qZ zxMuvzXFqs~NogYQV()}50D>ni;oo#3S!z3)_>SnTnB1aDL8iF5{Qe0TvTU68@0SA( zo-Hy{l9dF8<9D;>Y*}3Q6kHV^`<|@Tdp~-AWqLMeRTA8N|I#QiM*W$4Iw7}iFuwoc z#g|yiz&(|8@mUFy%}+bgk6mX0?E%H(Ck%(JCfBOBg><^n$JSP+hvStmJ!c{A3;O;@ zhPn3@q$};73awV~K-ww$6+V*tNkY!@iHED8giFAdKf|JX-^J+2h|?iuI+>!F_0G;t z#?=dur(HKfu~*Y}Np}TuKCTNk7K<{$jAvuN8lGpIcJ#EL&x zARioaP_FqmKPnoe_f%gGESQwJ&Uz6k+P?td342+)*JJA%+s?g>j=y-k&Zt$p4hOQw z@ln1Pp8Bg*e>}9lgIUd@r3keDd)wxXpE3@Lj(%iM(yR z?Yt54TSs5}&fL}OJGtZ9j-nv+^Wkh%=~l>hymf8Areo@1wPfGtOKw2h?S-q-g%F?Q zWwX-t^PdyXwfcHBM@jp}=H-)1O<(;rUB}!<*HJIF1QyaI7UFn4uHD)9NzIUs`%1YT zmnW2Za@v7+*Z2ZyVH=uNFr2O0_87 zt_>$sWwUw9pCd0jCTKYjJ^MqlyP#h>!b7lJC2=#VQx%WUqxkTa3M1PbBor8Wt7QHO zcsep#dquKc(b6W*; zpmM5HZ8_Em@E~$sPF*gn0};7~r1}=wi$i@&FKBGWduttfo@YQz^NypbdDX?M|E_ZA zJCKXZ{<$43i>>v-2f#IK0tDGjrQ$C}`etl%^SbY$PrXh!7knl&o#MJ8_9Y^+0^63aAgRDj6M52V=W4uFW+j(h3y|k4(72)&bwp$YD2QaR_wg+ zjx!S=C2|Q!@>Tce+uc!b7n`qAblett!c2nm41iyazyGihi;8x|zw0a$Q9q7pz2VzmLcl6|4@akfYJtQwPDAy{uz*g&ib9(ouK{p_H1FD zzQU%`_sIbQa=NlaLTx*-td}f-btdZ)9%a62g`|RppRRvJHX^P)GWzVjK0F)Wwa7)5 z`T3AugQCC}kRVw=;s^i83$j);51V-9l#eDVz(AMT`cox6C-m#?mJX%)@Gxjm8Qf7< zm{k}P0c7Sss5A3KeOgha6ypR@LRc#EtjNHWF-2zjrZ z3C@kMm@iNbnW}SBg;1hAB$eT3MYjaen=gGMIzBc1H4uYt zW{o0NJ__J_Htz*qk00_r`goh`d2wJGpXGmNAx9gPdfIwR^cp{cLz=|xgY49qvUZLG zsSe2ep0eMgT{2n$zNc3cxi|m*%0B0U{`PvfSAD1Ypc2fsQw3f?5iA=xe1=&5kx(=l z<~v6ybBSoY;Gc}d4>>@(7>~#AIu}K1?gMhCZGcY*Nw9K#$^kM^03N$jVD`J>XgW-?Ra&?-9AlL+3sWO-HG%|~3)D8;CEYP71LqqR^vaf8Ewa}kOR(RE zo^#`RorM2dphG$Cx^TBW`9|K=7i(EwTpqTy)dj@AMf`AOn0ZidF)jF$(M3*=hEk!D z@loe7TGdGXr|e;Asu!~N^Bq4*T3KhK8ihZHyW_V%HjjkAJVA%>Ur#zM^TDq?&{=;U^_vH<^X_S>bIpC350?gDp6xWwVw=$7_tAAuI-yz)3im_I zbm8)ah`uK1B}xRn_7_{El=5~|2^((x^K<59sl=Vq{|{Yn8CJ#Oet#<>0@B^x-7O&9 z-OZ-Eq)S3z)7{-A-6);Xoq}{XNW*{l9zEyxym(%D>E#~w46|q7vDRlgpe2g`X`nc&*rj<#|N2*j@3IL&k01OH`EjIVgo>_>)8bukCy;&Hj(ik)+1V6y z?$?XUDS%f0Ldy9iYWbKAabJ`wlFx`#0<|eSTC4_f5U?ey6LEJNt)R(yW^m8JK^$BKj4$WsC2akx;v<;y7KEq#O4EFaS2;~zr0fqkQy00GF{-}X+p)9OT1(jvH`MK!sL~ZckJN~-) z(H6PxH6#g?)UNuHI|C;Z>`Jo(514v+1Mchkin5nfgHKb0J~#H8bweMY61|M(kehs+ z&S&|`pVFo{QoV7b#3xTX9ucuXQmyRnPU5@{nIUAN9=@UZj8<8K<+r#SSN5F>cgXmE zSpZ)!*@(^`bb)Z!A=|r6)L>gkgFpH*x zN59_<@F=dg(a-kUE{qW*g~TK1_PQ9bE~{>VJW0b$rQp(7Uy%*Ev;eGM!{IvObh5)tB3pmZ#JY2Pl}L&vyqb`Gvj@L%J;cgNup@Lc@@ zl8Kvd#|aDpjpTPuAC&TO_a&GEVK}HtFIo&7Qzm+C>Gr zJ457Az5|(dHa|O`>3&W*x*c2uf!rV_s5am$(|hCRFh>NdBnuY;46z*<9J=6rRv#G3 zRYp3Afn6!H4}i^4xFc0NIHlcQM?vZn%-J;l1h|0I-*dc?U~G#;NNs!?0BSLEw>VZS zU0VtiumKoHt2pGvJN7fucIQ7d=kuIhFw+zrxhp)vD9Eo}N&Uj3o>A?3SGKZDonz=# zK$+z+Y4?g@->O{eI}J#Nq**|8Su+pcJ>&fK(5gw*s%qZP09%fkejux0HrG?TcvaG= za;PtE6?sQ&y7K0J_1X3iUo_#UeTS2PcG`ukyZDk1gSG>QtxqM{k_Gb>ynhvHOn zQ$gw~uP30B1?(wsil9(?&);!?dZ3Mrr7J%Ju$2)0`EOq)jQXX>SlC`|yxHvtKw#^I z%fDVo9}9o$P38RhJNAtcd3BCuXi)!%Bwm0W;-%nP8l)u3*F#})el+TeOpgl{{Yx|K zI2%IG!)gUt|3rB%Gl*R^SrWl|<))sE+;`Chzt{Pcm6UNLO3d8`9b?yk#}J`zs|$Nm zt-iyUR&7{<=k8 z<7}A0_DzlivNKMEeK*8ne3Wc#J0~Hr-_4ao-M`%GDtb%4ajyQ!ETV7ip1W7^5myR% zchI<(Y+bs)SDAssxYR*6Am|D=V$7+^8)E3@)z&v^3xnJ_q!U6vYMrc@m8^OFssjr9 zbOZO&SGRz6|J8>Qs-Jg&fxvzz!!`BZxr!rVD0M%N{JP;!>EZ;x9J#p+c}z$n&rS;O zqklIhJ>o%Je`mGlpz*ltYW%V!LFs`Ck|ya1(E|4bp`?PUKU7O<#>`uWm}G2vqhNTJ z_c%$&2wS#}4h-*w_vFLn7aHfty71P;sJ1JM$m@_zfJ@$155>Y&XisZyh0_k(HztXAMW+1n63BAKh_vt{BWj7n;TT9DM!;cb`_^?gA+ zG@udv?K=@47JiLanFnYRrlY6rZ!nV3gv0Y>A+0^I95NGCq7YlBAn-xMh29)qnmr<3X2-!POC+px z2IGY*)^sqa7S+AoSP~%YpqGt@R07@nY~)WvmBQN@PBBsui#YI)n7QG5w?tVb6E61= zw`8NA0Fn8a(?uCb^RfNKu%yfDmoU;S@V3K*NQ{A+B5FtZhUPcU zwkRjjDxwmXm%1M1NSYbCM+9P>P%FF*@MR%h$F+*a?=f^LXix6W)MvR@p(E8|)n@E_d6EHizo3Mu_ zKEegh!JI*2?u8dO1iC%6II=4(T}R(=1VpD#q4$EKm-!n%u&^pAYSS}28H+l!&R^tH z6oDUQA(VQsnyp%m52x7QgChsHaSGm|6$N{^y(M5NfMSCTGhXd*k=?rGkaI>`h0I0o z*0yW(3(P5Txb6G#j`QlCm-LLweQGqiNmLEAjLTowesli*B75f++U!CI2KKBmBx(k+ z-JS2@u=oPiw!FguOnih55z+GXHn1y+>y#Mf&`Z-rz;6zs60!6iVhCafDLD!%xG<7k z<3ohrGym0z7yc! zg)7To&ZNm5YL?yE7UKG`_JW=}Qoz&JQ|g(Xgwqoi+5?Xl(GO6nU=7>sj0lQ{V!Zst zhS2Y*cxBTOHr!o=q!H8$o5xU)dLBX=1--0#@xN6Y+xyp91lgLhpUgywJRoZpjj=b@ z4a5c}u1o1%p&;0j3k>ffrNTc;S28VjkAF`8O;h>(Nvn3cj@Oc5F$!34A8JAuZ<>zr zWO=atS>1&SmWdNN8YQS9CP4g8Q~A$E&-X24{PF|(XzZxse>*P{F~LFE9)-QgzpwpF za;h#UI5?ueMz@Fe-xiVx1iV-TF5$TNzZD^Hz-e@yQIt1c%r|HP!;M50h5=5auQVT+ z{FwzNpoT5S_p-S3BWqhnZ^u&AjjWxu|M|JUDx(C;T;5WG4fFM5Q!`>D?6GnG5uO9bo-=N3BqPYSOk%kOB39oufgSkd*U|5Nq4jv^zuYM-@(yrh04k zvpjz`)9w5aUnjRs)luKZ(u@*M)|CPO>9~}e)t_En10f-mw^HHJy!jtdKu2bPU|DVR z0)7YtBcZhAbUY;GrPtRhIg>qS$xNFvqzxUb^OdH^DwE$F?yH2y2TP3ERSOG=W6cY~ z>tT#-OkspU+P!>}?(DvwY;yj&Ca3Bm*{U(PL#E`@U>Yha!Sdp8mN#nE2+NHkYQ+_( zCDH)5@=aLY=tU0R=s4G<*E13AN_{Po`XkI?iVafStRh!9{>mh`{j**m&&g}SllLY* zWE{SAV2`dzraSI;gb8ItmHO=~UQJSGfNms0#p-CW{@0K0p6sS3EC3V6S%$T-8~>_kP$9ndWpl;1a;nP0kVF`sdz3(( z5wX+jl5x#E9b}i*Od{cyWugN@rfeKqom60d6Unze0OkF5Nnn22KjC(~$AY%YzM4U850KOi%DBThE_ll>Tk-Aayz!XA>dZk`rx(U!OQxJlAm}0rvGUIG% z|Jm#VkBd4FM`cY#Fv8JdPD6{-z~>P!w@_A=$%wDPqCOA@l8(gS>yNb3Aj}qMi)A^?Tb{o$^dx z^*Ys(Q@Sh*=r1$k8+MEJGJJLdtQ(=Iw4g+xLA!ihT zg$*P*w+tD--x3`zGYArZ0S#G;P{(qMOvfDO|M`R^iDu74@XJ33~XvoQHd6NAf?#?bz5!e^*nCLQ3)yL z`Ta~fw=v4YZA#zIl2n+Yb39ccUkE(CJ#r+|lb6htux=nKbg4Zdbx+(fZasa(Y&Yzk zqg@kxZOQ3H$YmYyFi9@$u$KRx*><@JYAff@@8tKY@AHQjCoRB$4Y}sunrupH8TQ=;f?3fq} z<5;YHey_2g^C}oo@jY1c`)YTsHP#{zZ+WSe^=S0;1LPqSM|=J5DRXU-bkNYa;j7os zT3{y@PCm=1U?hg6O2UN&6Cftd?~(Die9eyR3EIrdD1Mz%oOstS@ML)2*`Uc`HA`n? z?$wK~esewbM+Nqo1PQ@UP1sgK#Q*!uHLp2W-@`e_ET$Xt?UTus&i)iv2T^$V^BdZU8r@yo)~%DfanxWjA+8N0Q3Y_|w5F4W$8 zwiQ!u8*8ePwcA|pNb)^HU1jR|Z>g4fSAU<}7!Y4Gmp>7Du`xWfV@Bh&LfLpk2zx{_ z*4V9V)Ato~5!d3%wVkgvk*#s&J7a|$9`~oxeunA;2=~03me9WiO*NTVexH16m^V8t zpwe$$2-i*Wxmm$VAV_l`h_2?+_$u|>6O<$u&W^Q=hb z?3+QaSIl>pxJ()?-kAM-+N~bj6Qb~{_;s1OE}XzYBvW$qTP&)LlC4<3%`ri-jO}=A z(Pw+l>=ej4#LfeDn-m+xc~M=!cG6Cj^JaS)r%2&KR|h?qki%`lbPq=-?ExO+`)}@9 z@+~6PMqZTINm)*I)dH$P?Ke^LJ9yKKZ?EZfzxdC~g;Yjb@rC=gR#lBR`2pSNTef&T zfTc!oe{E#&>zhFdw-bW(7cgvJxwrHi#~>9#+Dml(fZIE!mfp8xl8#aW*5$p6el8n715u7b-g%#{v+T@EFq4L z-()f;1jD_#>+SCkK*<0MDhB79gQk)}9sFHe0VA}_Pg+HPzhsGDzGUTfPq*N_C=(!y zgg`6NDoh%9Z~EU-^tDpYx6GiC4+%HrVRaveh)4=wByDj7{k}U*fx)agGmpZGmLcz1;dA@8%x0)9FRRvW*#J2d8$R{SS;CS3b`#ae z%4u3rd<|H9MYz?hZKFF-w&eXO!t@FJ)I@ECB!ykJG~p;Mp!xMHi|34WsU0}YXdZ9r zd0j1KFCYl>D#d`O#)JiJ-5w+Y3B=%(JsSY_*eNi2q0KWuQ)6WmGQhI&+wZmo$mO zkL0RqdED)$K98~1mEJ3zw+;S z9vTA2U+9)ACW!od{P9I(1;?qy%2ywJ{+^NnqA*cIZ~sOD!OdD0RtG6zrSUQW<6#39 z263N?dw$pZ%B6thWGuIDHS|}uw-VHR=irFy!KcYl+ONxPCCmr)g9L{Xv9kNJm2}07 z7c;y1e-HfP+53zUgX@SB8v`|{4xJW_5!Xa7(obvLx8Z{8zfn;pENeqwYFTO+7WRdH zHZnh-jF^X`XW?*?dg<84*Rz)D)j&ykS#}6sGdz+L6qmGW(03f~_ zz>muM0z*6aDVFn6{Ga-pqz9RQFWYAlgBQQxnIhs|Uo?DKYfzdPh?LiZkBoz1T17qY z(-H@o^skDA+QW@x)R;F4kUW-HBBK~?pPraO z#*k*cq3B$D`EfF}c5RPP0J5|fydlR1h;}YGfHDbd-lX#Iz|ZhARmqXo3SC`1X~oHcGjS3&>GkaMI?=&|ZO<6B zdcLT%NtGhbs_2#(av{gCF7BsA&?S4Tjf6q?JaEDI9B>(}&VHoKozt3-p=5&?q_G+J z(NfaVYlUQzC>Qjyop;*p0H*^G0Ro~HzT?(sepV4hLu3Sj2Yc?mZl3wnIDr9YJ$ zaPtb1zWC1$DFr=M#vC;Uo{hQVXQy-OnjnE@th@YrrR(ALBD&Fmbl)=FzFCK40vU&F zvyVQo*j$?#Ryy?bqB87k#^0R_vIqijIZysqG9g1jxsWICMe zhozXsygG?i-VV@DbEG76478f;iGK_Yy$K`v@eGJcG?;w-V*K&#f4$zFtJD`ca@mxN z=h8$e?(!Gnd%T=#a^D}}b%Z{W{`Z5#3;|3mjM2$35=}$hOSR2yH_)AxoK4>P=v{u$ zb6az#)2TyBP(`=r)eVV4cMivbX%)3oeb;Dl661odx?iOXW?Ka`h7%>qln*bO7VF!Sp%@@;g5Ud|XazZ{ zoI?|kMM=%yRrg2OjIRR7Rq&ji_sFFHkb;%&cuq}`)yO^O6}MS+_)-o47$49Np-0V@ zPtfW47X3sg)@Oepl# z_U~P0Zhu&oTFJOK2>|ZD?giA*zLzjwTijW@4uEP~hu^%m3{Y)Gm=(SxB`2GcefaX_ z3lPC^F0ET$T`ZMHM#0U!K*O>_PE7n79bHJ|U|9n5;j0L5fdRN*ES)Pefof|(t!4yC zI1MZGoitv+y@|0gTQLJQHF6hjtu8m%$-#kna&mH7ujDnT<vZ zxyPy?9C3!sonST*ZN0TwAGG_6c(={fuDVk)CNnRGC0+fd&Y%+_dK1rMHz)aaU&h|^ zVQ*t1NBEr)BdgQ)aMe|rT7@N3$M@@>R^f>PfXoIDSW)<-rO{S4p#Y*ejv%nEVm=2a znYv#|Q~vxgZB_U!AjxIav*d`z+XN(vfF`YDC(GM5pNZvB$= z<#E-u8AgE%9-dAs0u4kHXMab!=K}aE@YNnSIl&*JYCTVyG4VxJxjcr=oiYnQu)~ut zNmT*4yfW!r6NmB}N7!Q{f3D z;tONoW}Elnh+n7>DYzegW@5q^xTIOX#F_y(=)U=l{=56>e|r@J;&CCzZd)(oZgJ}- z`hAL+4wbwB5k+!m2}v;lhvwszX4Xk^`2eF9ce^sW{_QS^O-zhD5o<*n znzF4N%4+*>phH@+V*5v};d^V2nx*Y**;olIh~|iifZL*u&OEut`zuZxYVwq;Z8|TW zd*xaicSUwp!mExE>w$NG_Q$6m+bkWq&P2>Ki1VII@ zv=U7eOOm;xEXOT6D%%j_=zaS1E@=4$7Q^K+J%PpTn6H?3yL|ne%<%JRK|m4(h8$)U z5Tkttk_$t`b>VGWZYgS6!5BLtdk9CK46TPOmxnV`5(%~~XB3w!jg7>nzL(|Pf4^C? zzc|oej7tY9}XRzSC|0d%=K1_}4K660XO)>u&Zry?}Rw zZb$$jtzIz<&wV=Pf5J^e4pl;wFno<_K+g+cwM|3Bq+km)mWntuZDfeSZ)UjS`Iw#e zmj^2;NV!R<4Rf_D0V?b21KL4mkxlVRT|wb=lbpiOFa`WXpd zH##y7nRMlomG2)(q)Or_{$3y=BtHxZTZq=PE&6&iLJ<{uYt$>ScH8${kd&Of7)Xl* zgnC%DWRbFgk!KWDTugQn5kRU2Ld0z#;guE-SJR={q!0^NZ%3UwyE>Q!Rr&>l6W5Tp z!Jw^M3#4r)j0b=%@%gz3eKrjhJUZVo*=QuEmLhWE%rHj8Z3V3~@lA7pM@Xai{QnN7L1HXz!a`)(jA)DFJLMB{ z8JC$EshB5*U7}zlyjj_PhZFD)u@7cLjtK=TY_}SJ#zOd-kjC&;5HUOZ3?8WU_mPY* z+o>tY7pPcPN3$1I_6h&FC;Zf+1gB$h`G4^V33(Y)1ZDmVT6PPJA5caeJ%=s1CX!2* zw)BFS#D}pDNs8AkwP3OiWFzrdLs881K!+R)5{Jcl?xP=KsycC-k4Z^=T`8SU$Pfj2 z6^9V`s=46J4`GlAp_q`ZMXnhtVeTMkZpv5C7Y!3VAoiVy%7mT?(7pm+k(qCP_V0Lq z7<1F2zjcOb)4YiwrgAbJV@BKo=;^)lr3(JY3?J?W^7^2YIoL3&vyBI9WMSqwG=AQ& z_89@P@)sQ?TqicqC#p!U^ALm9yCEua!(W}eCrzlIG7!y%d9R0>p&E^=zmi~nxF~0R zd}OL!&3-&RWE}&2mDt!V5k<#Am6S899$ciVjxOfWuD483I&wZ-J3V*g4rp zTNp`?>Z2%|=Mq}mP0hbPW6Qh! z@IVU{!H2TJm`-O&AMSZo!MLNR;v-)vBWNMf>}r5G)qnmGa(z=UfLS zD!sj!`r%!otbH!bQ00LAH^j-L!tLt zmf!pC;|3I*B^#Y+zn|UVim|hM_1G)dnO@<1W4S<=$>5n;?7hSuym^93{nJpHJ44rn zEZ-Qj^ABMXj^wcQM?CaOpB)8f{VHhG^Q*0adn5XT$^3*s0+kUv*iEqaeKqqPll!Y0 zc6HdDfKk$%(4+D=#DIJ5pUlPf5bxE?J3Ea4kaJObkVbHi60+m;=j9Nl;K}qvvKBLa z=Pgw+79k4=!UvVkPbVw*c8}NeURN{fh6j6~uO%kXBdH!{y|f!mu&WA43znsZ99q{O>-tVa z)Hl2}KyD69nHi$@!E-GDQQ*~^(}|S;0wo>mxLE(feb;d|EoV+L=EhZrRz(;`O*klm z@agPk)i*`&{xqZGuYg)L!oaJ-{u#I{>7QLxP&FE@SW^SQ0MUC zmu0dLSCxn+9J3G)%Got^yAq8Or@WdL6zv9EF+hzaY|BSd53m9v)x(2rNbnuNY?ShR z0lWC|R4dARnyLe*^GI_!q)H~(uOios6x+Igb}mzB!PRH{{fWRbQ|v`HA!1=nMhVx` z4@b@&Up`Jip$F>Slz51B^khFAV+JucMJ`PPf5v)sP1hIEidrU~^~ znk9QQfQ4C%A%3@!OvG7_cXH8HEEg-IPnx%~xWWrgJg834xUbz1J?LrMKeK+u#6Gb? z7!*{_l}XjWa>%KJ(zRW_LJ>x8yjU-5W z1IhJlSq5xi9hK1bGemw!M9DE!(}P%)FDyJdL_~}Q{zfJs;%+eT4u!<1wm0{i1ZYkL zowV%Uu!g=Tl#E^?cP?t~NT_#PGz57myJ<9-4Ubm>mtN`bWCP7lHy9||`-%v2d&G=6 zav52s1)=@5<5gj51Wl7(KUP(gzLJ~~GS{gm>2x6B=9jcK$CGHF%;qSWbra|AeY?!C zc7qD)Dc0Z%cdA_?kq!yJ3F{`_q)?oV-zQpOJ?k^k5MzcDf3@NIXzI;Df@YD8lN9Yg zzZqFf{qTCm=C_cN);moHK1j4o9u>PKq6__Zp8I}6fhv}$$m1>l-dt5-NajL>s2*z8 z15sNeU3`T1D5+2c)mf5T!rY^6y@{T8 zCQPn4E4G}gWuTF+n#gYtkHi9eQAonUteJ}tRutb;?JzT)teQppgGM$URN3Us8j==l z#RxV_5PzDHXrEb^O`w154Q&}C$4 z^^Ku=1QI@VUXpS>QWA|Bywp%bPU$x#xFGW52&5b(&43>a4C~kxY+#8)Hd=*N6H)sl z$nha-!Z0*qUKL6AUW$IBe2U4GsF6Bo&9vei6qG3uAT-fL^Z+?2p1zcNl_cdbS$w;s zOlYRzN@8GH8+4d&E$*Ym=6BaOvwlZFsp0TZ0t&%cWtEIM(^d{t^-(HM%X4$Z{LBhr zwx#l)Pk6_1)GHHuMRLupK?x)Q+naYb*)DaVA zI0=n5Q{1H2el~DB1IvsurL{j^kV1i4Kb!7uB9yf(Iad%<%kAE6-xWG-C8GjIb;@>i{zrE zEvgO#VBw3WFti^!4!hX~S?H2ZmYo$vi7Oh$Ebx2HuekvmG1<%^L_EN9Izq5DDb3JZ zKc};F=;EmrU~ogP+kysUF>(aqa}3jA+?nCAChZeR&ivU~R(TR3)o+@5s`b3h+(kMr zD{=Oy;%-NJi&DoJbN~&8{ef|SH>iEX-QJwh(k$48C zw$C>v(p~OoJz3Hph%2txzrX6F2oHMyX;#|t8yco)@{Nl=Lzsu{0*$d0bWn;z#vAH_ z_O3MY-vT6x=g(>wjzGa{L&+Qu6~T-)Tj`mj>lk1DFGoNJRq z45GkR^Qo>ASXo~eU46y>Q#!B_`t4>_>BZt&$i*r$ekA_?F@jb`ziY(84ucd=^~+j-Vwss1f5HhPlcokNYk%dy^l_Vep^oiUkEjk@ztw_&2$!^z8qmx1Vo zv2P7gk2Dh*?(z55ZC47UIgOUOxHxp`rnZkFAINKwX>HdKQnHI2X=7Uv1L!{Q$Xq|{+J;c&RyQTb3Td-FoN^kv_FK~|Yil*@ zy@n%ppustc~qYfa5!qmQsM+<1W^n8z;mmLr2w{Ko%o#gEdFEbQ}yPK(r zB6-4E+Iug+o_Y$9twY#G{9e3TK(?x_^Tx9t03mzvhSolgE}amGCZ2KuNVkb*C$ndM zHB+ELy4mfH8vb$OeSg{OjylHL-*NXse`b?WbEh6lke~39LVj`=I36Cn$%NKl?6>D zhBRH`O)tjvT%{ea)=Y8^21@8yqxf;D@t>Um{09?T_ohYBpQwysHm1%;L672*NPDsz zeAOse*st2g5oHh#uPYO(P1fWTnYm*p zqbDwqVs`VxkU!DU7%g@0#Wa1$?OQKWg3IEp&<^`{RaULHGJP8z!Qt@5q17#(oie5= z-E*{g9(Xb_Z8tH$xIL@wJB55PRh)l5cRcPclu??`b$bKyeR1E%_^`rXYrzC!?QM_I zDJkG3+wbsz3ur){@#gU&>zNH|gs!-}yywI9a=`sb>*{KzH0T8=HDDRH#aPSYb@P01 z?7LRcddw0Q9eNc(3Qy`Ni#biW#$ghhX$CUBKt~NJdfBEuvXGQxibF z$<0X3OvYhPxSf^ugvY@33=se`xFF5g9tgPojkdcy)*m|W37HN6P3R>m|4oOwn38(S z*J&(&r|_C{mS>;89m_mBvps>}p&qDPVqh2+ zG1hK-)9C!FBjs`bg1F6ED0{JQ+VH4`oGR`MH-5e9X=t@$XwOVFIF*V$<2{FzI2=dv zEI~bb0@c? z$wuYJBb?W3UhV1k1y_K*Zsv zEYCZm;^adnC(ri;2~7J6`(zuI0R33l#~LXJS0FXPPQCK&pWPKNp&v#xuEPihA_?*U zmW8bQmv>gPHb|=R_zCMrDh!rXmFiwa>q>#em;dvDg=h^>WGaJ6kk>#dFE+3k=fcA? z@T5Fk=ofO6Z5Lr(M~sHVFtdbsa?1A~QK%)$iwg(zZ{|+1F2oxSfM9k8F*45TG_{-| zbvvS>L!_oKPoszrZ$F60qGcr_r12%|3VjZzmo;IRk`4`=9uUd`z2Ce$;+-znLU8>^ zyibunRqjBVqOE+daCJVP7lkcP%Rdl>?_F*XcW9TGkzoURt@##+CPoj~gQ&fIbX~m5j zN@L7C(?r`Bn%0gpF2d534MRBHf(kp1x($lx9cz9JQ|bp2UB=Ql|sWjCJ) z?vJ4<>lQd4AT>?%rTOw1@b_a|#I-YZ4Fg)Ih)-sl$fS?-5`2=UFCKm0l)o^*C#{!q zbeY7x1U*)X9wMm*wvx}_{0n4!H@RZahib4=KYRMRC<%$QwN!X=xSVdavvZ1sFij8c zAgNf(|Hmzr3o5Om>{26U)}GxQ6dne{x!;&JN{XwA#Uc?SCyu*l4!}8EP~>MtloI;{ z8s_Z1@+1>_m>+r{^UbAN;{zr*Sgo9Hcuy#ot1=1wf>;y5)fzTB9X?n@u0ee^TWQ)V zvOu4-uuiDYAw;@$Bv+&6yVE2Pg>`mDNw`svq}K(+joGLOGCu8y3M=`KbRe;Hk$^e4 zbSOxf6uX3lR1`;z{D~PpNwy!`&8-21E9tZ{ay+AHvyAczibjxbleBpYQLgiP^gWYju(P8zGUK)V<|4uP7oTHDT zS2H#W3;cD1hEa65fn+|cp(C-KfH_UQo0ib}Cz0C3?P)w_x2_^o)O>XaZIVQuwS-B} zrs?7^+lSV|>ld7*ZR-&Sokr8EpDnJemc@nIo%3tuI@Kt^i00~K^Z|gF$>6^ik0OYe zDO2ANc)pEdUI8G)%us_~15*-BKpLgbU}$?BhA}XWt2Ko`{<=+x9iJIaD6kTp z34~|jrs0exl{S8pb?-Y4v1C1%YRr+q8NlpKC_J9>Dii=*HJqb55yuB`krKM7da?v52pgn0L-B?&{5AFP|&=wMQT$n+d z=;UqkNp5N9EaeUQAHAaakln2N{wn@d@YeF|9|&#(Xa(M=;EexW(VcbC~^xVrx( zV7-HTCv)TaZoOJjRy5C)0!Msm3M>Zr3DzC)mF+V3!;Io=(rB#2c zX7NWYXn;usC=Vo&aIqM`9aQaP9JVp$Xi3(nLPklutzXu)=nSumAy8n#bTQfk>71h% zD_8*y8!0pOn-XeG^SGY~HpVk2Xqs=oN#vqVY0NW7vowi>D(k2PN)?rVB+pbrKUY}L z(FotN>MeE^CRQsSOgdqSd6*s)O0P+6LQ0oF*@;;w!TqtWtf;iX*7=~rGN$F>FxaRJ zIv)=T84{e9g526ql|r?Sf-H*c5szg5ZpBzl31;Y%C3AwSmv@k4t^oYr8=bI)0`F-WQR zm2Q_*GfxwqiBH&F6LGx?K;)VC+V#5vHs)!MO?16OmEYj{60iZH=HZMLBk65Uj&t4K zL_YyLN)8~EGaC3s9Mr?denbsKkMw+!biISwk?8;ek%NI~TBB_s|7e7Ljt$H90ejPo61yvS3bJUI3-7(5?*N^B}VsX zENK`QcN)Y^#b_+c$W0^5scbPlGpCKgyrhqXAxrNm1y3226Bhn7#4jzY_$C!niI2#Clbxdci%`nmtsEOg zpGsrhK_OP?%?5tV?xH-H6l_o>0)t``LYKGKcYkUoVxe68JK}oI=Fc)j0P%GW#zYZ7 zySw}m=yfPK7deS6ur|rB+HKT95RCrJj8$yHsC994;Pwo)37Iw*LbX^+Pz1ZVTk;B<}D z7+*eX=wdYGER*}kBD+}lZ1V>c?$mY(Q6i5QG=|6tZoQ0gbi#F@z2B9EQw?<=D+{vP#(uz<@LclB0ciPDQ zpO<-(j+YLO9D7@Sa{2FHk>DX{LPMa~ZT?lLQ9-oQ0~#-vCFMNSKk8I~jqYa-h}2Nw zEf>Z9s$mo$U9?}cW(`GRl!bq_U{nwjMA@4ZIMa0z|7SSe@FEbik&lp*`R~QK9|5@; zTd@W1-(~9mriXwKZYdKdBl*7Q#D5y{k0(gdRvR@vAsB#AtLn6RYW~h#95?oCcOsLW zS5f)lDZ^WuWzd*B?iKt!MQCWqdzGA`yYf&1+Ofs9i@My|IrT;@K^ww?N=qAExwox` z+BP;bE!t&jA8da)LTZ{=%qImNvZi=@uioe71i`|PCf1!iaTx+sdmH|4?q|kppOf#u zrft%!qvg~5;#taB#=f#H@V(Q7SV)&S8BK**(R3o971I6bw%e(1uy+yVNcby|x@eu& zsiL#EdSgqZCI0iDu&CGMpZ$Af8PY!T5Cn8@P>6BEi6T6I7V3*d|JY3!295LnT!qBK zc8oKo=oF^DA@}=t_%n0PB1iExXI@1erEqf=aLu{YO{lcuA??PKV|Y3;i{^1wi1^o_V8nfuipD~7h1Ae;*wH6QN(05fWA5Z-IEn(u2QJ3 z4AnDLdt$Kvyi{ub5b#K@=Tir=WKg?(<2T0IgK_?p+h&W@V69`OcX8)MA&S0dF0}E( z70Gg`d&4YxqnTC4f*a4}TkGW&sZdSaPU6hUijPQS(Yt?=t6l;ipUz(13NH_;IoKFW z!y&sXA!y7pz&pz#sEZVwSol@rZskHo+?iMb=QF*XFsHHt{nw-Und#6;rFKa}Fc1PT z5W$Na&}&NS$ETIjP{T@J_uYZi(lS6s89k@90Q-oyftAQuG<1DuDGT%zIpWuJ3vz8qe?a;6px>O?}$E+Q3xe=y~FDqyhlzM`~`RY zIwnihBlAvW`A1l77wgZf`u^vFoDp3XbuOQ>E#%)%X~@;F@FTd7-ZL{Ri`4;n+ zbdnEDqxUn1Q~LS2<4b?e1w?O;RCld09k<=ve*1oC(*t70^X)pj>Emqk1H#gO^UV3l z3*{ia6yxdMzZa63d>}GC?x;W2x&8v`7cToL`K#LvUpG7eXVM4o;fLK@cv=-S6>m#2 zl@Tlc1djZYK%vrDj^{ovc3Jq9bJA;3tF&lrn0IqJ?m1QWHHKZu0S)~&T7s;~d5MEe z83wf(CV1W6UDw=7KG*$(0Bwrz(8<#rqc9sxzFTBiI=Cm=UF8u@aMW2Cfm`kKND+=R z@%cw*_r&<3AJf|yJWg>3BPWgUwI)U?cbp8y+iU46%NZKC-8}~;t;^1LgqMpp0QB!= zo(DC9z*5QiRDcXHts-x!X=#Pk)iIBoHV{xp=G(k^zv(e_(gTb8WXU_)W|H-8$rI0O9YAb_VlKUMc`jPC-@wq=jPX$7!- zZvd_R7m+p*zQG0(24A-wL`6l-&Jzk_C3m1#ntVDyTf0aL_6g|g6T3)_pze3S*h!(O zE6Vb~0aP);_AykN?0HTokFoXU6C_;ta%`NOMmMKxO`uV9dzQ%}>AxXGzA$KXwlrQ! z5A+Dw%7?NJLJr*mBbU?G%T<0BMNHltYM;)kMmhYqkogi1Zq|(uRnL8%o1gP*XYc*4nOU=ER_GH|;GCl84Cf4$ zZy7$e0fhUG>lklv$sR@6P~15^^?K(^kh~GkEZI3zU(vjGSK-%pO#M=#uE%NF4lq(F z&x)sD8|a*vuRfdc#VC7l!hHcbmqF6>inH-?@UuNvy)(k&CO|&mybu;w{}iC)^&UKE z^JPl!>Pj+H>gG_T0w~`{;*m+l`@o4${!$A196*|9UgKahJM{#z^=oIZ`1J!~nj2Ov zd%ex?Q(RtljRJ2|+$@>EJHxzO##{)i)1H_XWziX91ZBk zBRM)6S{v_QMT?$$tvUUcTFf)v`-KFn9o}?$v@tC(muC+x5%okX!FsAN(1U&My^V_&2$u_C=SCk*F!8^DNocCV zb__Xn-8-u(^`>{Lrd8*Z#8XCU=AXxY!-SrhTO+$^H(%ztP1nsgZj^6KF1?JWrD@pD zedal~GAMywh@Y-6d)HTl=3(J(|A#;Bmf;P7h==B^0^;%V-|9~U^8npJ8nIt%m*}tw z`(d@JPsMfjl6FVi#&B-(J~MZslpVJVu<3G7g!nk*x3_#a6&{H5$c=W8=FU3E(s0n2 zaS1K|oSM38$HCOb?E<{eum9eDt$!;qHF3kL!RvJlt2*q=nCRRchMb=79!!w2Jx7F| z`|Zm)T_-k_rimX)c4%zx))FX$8Ty_QORw7PA#cJ?Il&W&UG|!|Bj+9#wh+#(EI(V1FcRXw1*q?OM^WWH$cb65Eh$eHJeg6p- z=%bo2cnG=g)zac~3cU`R_ zx~N6rCRLqBE6JsimNtsW(+T4j@4kPymcgRCFe8@j;ywVpcHYbPmFx56P4W8Nu)=KB z&Fq*P!cK2n%|kRip16@15sK57qpYp~`Dq~8OkeJLeguZFW(lC!bdiI-siKk=>Bn-p z_~n_jb-T8)hajgc=42!>WVdwD(EoW9rQn`9oNrz=2ppgO51u^ z#$~&d`8rYG`1y#4KlTR$WImkE-v_Vtdw)*2j4JD$3ZkFjr>KUtD>PH3=cBdBDR4v7 zy}MyAh&sBpLk=7tbedKT6354v@VD?MFbnIp=#K+6w}t3;H0tKjGv9-b8PU1vg$r1D z8*j(?qNoIiAZfEtAo?=RX95ujwiN4P)ye)haXG^mP=)K>@Y(^Oi`+%8+Bkzp_Ungl zjo0Q*_v(&k>RMT~-`S3?A`TY4gQU!ECx$kx#xl)MZIo~BP#ZJzew`M%_x{VdF2i)M zwCG*EFt>{lQznLrDHQa+c0kpz^Of-M%idQ1r+MR^z+2`lp|{G4XZ(FRviq;5duw%e zHA*XsSk|k1{g1e#1(B43la&F?cVEKD-7((Tr{ zAEizjgvUimTKtwuql~=Zc$eb~$>z%E_?aM9nJSXTr@am`TfGg2{6%~|C+oWP>Sc9gLHijLhFU`=-Cv+hOX&0+^FEsur74Fw< zUq9NYzya!q4XxStE$Q5~vMdIrHwyoY!oR#}R?pbCf(JiMRx_<>gHn)X5T3M-?W=IK zlupd5{p2k9BQxqi8lH>Fj{<$Pp}x5YHo-Fot{7QSO^f^VV0u=WD_B$(g9)RUoZRFY zjJ&-GtnMJ;@-K1$=rD*4VNPhoyb_BwWP$+ z^c3N|M9UuGarbxT$te`mD-#yG8kB`xm!zXt70z%g`nAcst28y+SgR(#*2)Ao%6)%( z&OZm_PYSs5#?_GSj!BPrXg=t8fM+5S-5?p-Uq)W)NY*p&Wru&CbEnFOnDxM(`uj5k zW>x3KU~gZ_Y+pDnB5}nkS#Ebh9D&`9{m>N#X_nfCQMwUOALQH2O{IiapdCVk;`&1D zxCpA-cI{RC;#{f-d&-gcCeuOwFqpw$u7S`I|?sL{812Prguu~)AVEt>fM7vv45D@jqg95Xohscm$*C>G8WYOC^|JZnlHdS@gpc5 zO-r2v{M3NMb7;PXdz04R}qn%*O z7+Gt)plAj0G6%}pdQmwDp4s_{ItE!6QNn0Ioc6=>8n+x2{CV}iZt6VaOulfHeg;+~ zU=*#Q&)&rFDe5a;0Buu0y3satA!sv>oz#@om>8MrsjVG$^ zRy~gyCR+KfTn>0yJw;OoW`XVevn!hr5@)XI8ZmC>2~#0)le$}O+iR~CE-}4qecO)P$-}TdZO3{ zLwbnoLY;#N_rkEdDY$vm$Sg$FK6}qX3(?W}>@~qevaEc{@1fef!RVnb0%6si=po$S z!R!Ne(6ZC??hqraG)x_4nrdP*I^~|O3zAl{z`5j&r$m(h&D>l+&qzjMVX64Vi|K*Y zMiV3!H2%&%1Z>QG-OOozX(T;7vY*R*Oje@JB=ir_8%j#e#K5d|V*{cUNCYj8TFPs{ zNZ0Y7(d#w5L0~=WrG4m;+e1r-RZai;hj)7d z7>?5Za7QXcmtwPS_SU))6gIZg+RQDnC=B!v<(?|F>&EW*hA;584Ypj|Mbp#d&7uN*Ohu>o@1c4MGSehL7_^!l#aPIGZ8M3G|sY+VSs(>75-P2-o&uJDxE=fm6cLkXTa|K zP>@MauGF#=eO-0fb~y?Z6TtiMjY!0x&3ubWRBq-N3eso-KFIjmQ^gY?rrVN4uv%P- zy3DVE%yTNqw6U8{22&BDZt~fdBqko3o@9jZ)U(RU+5&0G72dO%n!$PWquKDIM*s5+ z2e0T06kO}KJ6X4Z>Wkg>Nh}mo+Ci9`nj*^(63zYVAd)|Rym21#I3_8r@nqWvmX2=b zPjqqHRlt&MxwCrOG2hzX&LReaf8>V~gLCwF%{-85f`x2Onig!?{Jj0Ys_DgTG;QV9 zFix|xFKqX4-6l6RB%anQ1ZqBK6IhV)42r%+S8Sk_-Oh&*7;Y)KcFZLsp?I8Bo+Iy@ zc@ZUnebyFwsrf5we}?3h8nN8Ct+TCt&tvwwpb?X`)8A1>^2cIrz+2$kf4EV8bEr+8 zCfDjSdK{b+A?b5ubMRq&Ib?7dGiJd)QB}hpNcDok#8d)?S4*n=l&d9=HROAQ0m_T+ zn}m)i>)_BR1gB4>r+lon@RY2G05a&Y}b6xDd|A&UcY_$JeEJtnjH=n+faoS!v6!~=RB}hn#x(95T|z> zt!jb}FMk}yAWbh9J(53EnU*ZcVy7iQE4w^{Sr1Ef?X=>pJmbD;miX&RKGQqX-ZM<^ilxLFl{Ki--WlwU0@q#bSmi|$NqA!_-5bm6* zx=h6pFr+>@O4#UXdeS=<=3e;dFF&o7r_$zBGB|4dlDtG+TDRT=`HtW`9czRf&RoAf z)$5!v^WhROJ`oSSrgI08g2W-m`MOnN1%zA%F3NMuLN$Y`36Fpgy3y5H;E6TRtt)s# zL7B7O!aj?L1UuZv-jEE>82&3KvH+Q3naAdMcUk17eDRf)q?>~L71lUA@KsLN7iu>& zGe@Ws{zL@9w4nNPBx1eQ6zRq~ZWJ}~!Jz_-*?>J0h*vWcdz%(S-F2^mG&Q1ts9p8Q(*`xGz30_ z8t-vRDcLP)4hBK&-f=8ct_`aseNpo^8%V+Vrp)v2qPm!*)m=WL_UL(^l2Y3lUhJU} zlq`)N4@aPLx!`2kph9ulg#7Q_JAN{$@!mdsJqj{q7R{ZzEzHvH=RU?| zZ*)8$j@4?yZ@?!Nw*%`DwEW?qqbSPa=IQ_w`WdFC^La%d6IMJ;MyDp`o3dURmXx#;5Fd zLU1lAgaL89*M(xF`6_d;lOs!S|1c$k1~1zOqj09&K-#SuW&O$)4&}o&TAp-NkEe=b z;%T8-Lm!!A44;!!2Vde~*FW;WT+9^4)G73?~ZC(qp(XX~N_YXrWX zb)N){n>c+1_iN;wfv%GbN$S3Nnc{+Ou4!I zkYw*oesCrDh${&rVw-;zOTB0F z%7V*y0L9$lfUmfH4}DbnQ^GI~#Gs=R9&d{1&r*(OPw(~Lt^+5IOR^Dvns^ncGqs?8hK>gHc9K;5m0G& x_!7Y6&->R#bN$uAS5lQx^}h@G{}=c1>|))k=Js}-lavd<53XSVD_64){SR6UcHRI0 literal 0 HcmV?d00001 From f90ea705c94f942608c88809f5b759e7bc841239 Mon Sep 17 00:00:00 2001 From: liutao <473139299@qq.com> Date: Wed, 30 Mar 2022 10:00:25 +0800 Subject: [PATCH 101/102] Update custom-resources.md --- .../extend-kubernetes/api-extension/custom-resources.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/zh/docs/concepts/extend-kubernetes/api-extension/custom-resources.md b/content/zh/docs/concepts/extend-kubernetes/api-extension/custom-resources.md index 307a31d304..e2021c4043 100644 --- a/content/zh/docs/concepts/extend-kubernetes/api-extension/custom-resources.md +++ b/content/zh/docs/concepts/extend-kubernetes/api-extension/custom-resources.md @@ -51,7 +51,7 @@ many core Kubernetes functions are now built using custom resources, making Kube Custom resources can appear and disappear in a running cluster through dynamic registration, and cluster admins can update custom resources independently of the cluster itself. Once a custom resource is installed, users can create and access its objects using -[kubectl](/docs/reference/kubectl/overview/), just as they do for built-in resources like +[kubectl](/docs/reference/kubectl/), just as they do for built-in resources like *Pods*. --> *定制资源(Custom Resource)* 是对 Kubernetes API 的扩展,不一定在默认的 @@ -61,7 +61,7 @@ Kubernetes 安装中就可用。定制资源所代表的是对特定 Kubernetes 定制资源可以通过动态注册的方式在运行中的集群内或出现或消失,集群管理员可以独立于集群 更新定制资源。一旦某定制资源被安装,用户可以使用 -[kubectl](/zh/docs/reference/kubectl/overview/) +[kubectl](/docs/reference/kubectl/) 来创建和访问其中的对象,就像他们为 *pods* 这种内置资源所做的一样。 ## API 服务器聚合 {#api-server-aggregation} -通常,Kubernetes API 中的每个都需要处理 REST 请求和管理对象持久性存储的代码。 +通常,Kubernetes API 中的每个资源都需要处理 REST 请求和管理对象持久性存储的代码。 Kubernetes API 主服务器能够处理诸如 *pods* 和 *services* 这些内置资源,也可以 按通用的方式通过 [CRD](#customresourcedefinitions) 来处理定制资源。 From 0561eaa17a7ccaf7003f5d9ef9153ad657c74371 Mon Sep 17 00:00:00 2001 From: "Yu.Bozhong" Date: Wed, 30 Mar 2022 17:18:25 +0800 Subject: [PATCH 102/102] [zh] Resync kubectl-convert-overview (#32642) * docs: update translation * Update content/zh/docs/tasks/tools/included/kubectl-convert-overview.md Co-authored-by: Qiming Teng Co-authored-by: Qiming Teng --- .../zh/docs/tasks/tools/included/kubectl-convert-overview.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/zh/docs/tasks/tools/included/kubectl-convert-overview.md b/content/zh/docs/tasks/tools/included/kubectl-convert-overview.md index f26827f2c2..9e277732d5 100644 --- a/content/zh/docs/tasks/tools/included/kubectl-convert-overview.md +++ b/content/zh/docs/tasks/tools/included/kubectl-convert-overview.md @@ -15,10 +15,10 @@ headless: true --> 一个 Kubernetes 命令行工具 `kubectl` 的插件,允许你将清单在不同 API 版本间转换。 -在将清单迁移到具有较新 Kubernetes 版本的未弃用 API 版本时,这个插件特别有用。 +这对于将清单迁移到新的 Kubernetes 发行版上未被废弃的 API 版本时尤其有帮助。 更多信息请访问 [迁移到非弃用 API](/zh/docs/reference/using-api/deprecation-guide/#migrate-to-non-deprecated-apis)

Servicio de almacenamiento en la nubeVolúmenes máximos por Nodo
--default-not-ready-toleration-seconds int     По умолчанию: 300
Указывает tolerationSeconds для допущения notReady:NoExecute, которое по умолчанию добавляется к каждому поду, у которого нет установлено такое допущение.Указывает tolerationSeconds для допущения notReady:NoExecute, которое по умолчанию добавляется к каждому поду, у которого не установлено такое допущение.
--default-unreachable-toleration-seconds int     По умолчанию: 300
Указывает tolerationSeconds для допущения unreachable:NoExecute, которое по умолчанию добавляется к каждому поду, у которого нет установлено такое допущение.Указывает tolerationSeconds для допущения unreachable:NoExecute, которое по умолчанию добавляется к каждому поду, у которого не установлено такое допущение.
--docker-tls-cert string     По умолчанию: "cert.pem"
путь к клиентскому сертификатуПуть к клиентскому сертификату
--insecure-skip-tls-verify
Если true, значит сертификат сервера не будет проверятся на достоверность. Это сделает подключения через HTTPS небезопасными.Если true, значит сертификат сервера не будет проверяться на достоверность. Это сделает подключения через HTTPS небезопасными.
--logtostderr     По умолчанию: true
Логировать в стандартный поток ошибок вместо сохранения логов в файлыВывод логов в стандартный поток ошибок вместо сохранения их в файлы