From eddbb00cbe2ce040973bef4b5583239f5c7f2391 Mon Sep 17 00:00:00 2001 From: Celeste Horgan Date: Mon, 10 Feb 2020 19:55:54 +0100 Subject: [PATCH 001/111] Convert to {{ note }} shortcode (#19054) --- .../run-application/run-replicated-stateful-application.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/content/en/docs/tasks/run-application/run-replicated-stateful-application.md b/content/en/docs/tasks/run-application/run-replicated-stateful-application.md index d3d341cd0c..13bebe9f53 100644 --- a/content/en/docs/tasks/run-application/run-replicated-stateful-application.md +++ b/content/en/docs/tasks/run-application/run-replicated-stateful-application.md @@ -18,9 +18,10 @@ This page shows how to run a replicated stateful application using a The example is a MySQL single-master topology with multiple slaves running asynchronous replication. -Note that **this is not a production configuration**. -In particular, MySQL settings remain on insecure defaults to keep the focus +{{ < note > }} +**This is not a production configuration**. MySQL settings remain on insecure defaults to keep the focus on general patterns for running stateful applications in Kubernetes. +{{ < /note > }} {{% /capture %}} From 6ff38e05c8e98028c759fa45a943d9980afa816c Mon Sep 17 00:00:00 2001 From: Cory O'Daniel Date: Mon, 10 Feb 2020 14:43:54 -0800 Subject: [PATCH 002/111] adding elixir k8s client (#19056) --- content/en/docs/reference/using-api/client-libraries.md | 1 + 1 file changed, 1 insertion(+) diff --git a/content/en/docs/reference/using-api/client-libraries.md b/content/en/docs/reference/using-api/client-libraries.md index c00f7736bb..093490b345 100644 --- a/content/en/docs/reference/using-api/client-libraries.md +++ b/content/en/docs/reference/using-api/client-libraries.md @@ -71,6 +71,7 @@ their authors, not the Kubernetes team. | dotNet | [github.com/tonnyeremin/kubernetes_gen](https://github.com/tonnyeremin/kubernetes_gen) | | DotNet (RestSharp) | [github.com/masroorhasan/Kubernetes.DotNet](https://github.com/masroorhasan/Kubernetes.DotNet) | | Elixir | [github.com/obmarg/kazan](https://github.com/obmarg/kazan/) | +| Elixir | [github.com/coryodaniel/k8s](https://github.com/coryodaniel/k8s) | | Haskell | [github.com/kubernetes-client/haskell](https://github.com/kubernetes-client/haskell) | {{% /capture %}} From 51a3c3877b6149ad9a0d8718201b0bd7b80ed7e8 Mon Sep 17 00:00:00 2001 From: Zach Corleissen Date: Mon, 10 Feb 2020 16:16:01 -0800 Subject: [PATCH 003/111] Remove ryanmcginnis from OWNERS_ALIASES (#19062) --- OWNERS_ALIASES | 1 - 1 file changed, 1 deletion(-) diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES index 52ceef1f42..9a44dddfb3 100644 --- a/OWNERS_ALIASES +++ b/OWNERS_ALIASES @@ -50,7 +50,6 @@ aliases: - kbhawkey - makoscafee - Rajakavitha1 - - ryanmcginnis - sftim - steveperry-53 - tengqm From ae7ace0f71119c13827b6447614b15ef9cff6520 Mon Sep 17 00:00:00 2001 From: Naoki Oketani Date: Tue, 11 Feb 2020 11:18:01 +0900 Subject: [PATCH 004/111] Replace links with redirect destination (#19038) --- .../overview/working-with-objects/labels.md | 6 ++--- ...un-single-instance-stateful-application.md | 2 +- content/en/docs/tutorials/hello-minikube.md | 22 +++++++++---------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/content/en/docs/concepts/overview/working-with-objects/labels.md b/content/en/docs/concepts/overview/working-with-objects/labels.md index 606b0f3f67..a74e219103 100644 --- a/content/en/docs/concepts/overview/working-with-objects/labels.md +++ b/content/en/docs/concepts/overview/working-with-objects/labels.md @@ -72,7 +72,7 @@ spec: image: nginx:1.7.9 ports: - containerPort: 80 - + ``` ## Label selectors @@ -92,7 +92,7 @@ them. For some API types, such as ReplicaSets, the label selectors of two instances must not overlap within a namespace, or the controller can see that as conflicting instructions and fail to determine how many replicas should be present. {{< /note >}} -{{< caution >}} +{{< caution >}} For both equality-based and set-based conditions there is no logical _OR_ (`||`) operator. Ensure your filter statements are structured accordingly. {{< /caution >}} @@ -210,7 +210,7 @@ this selector (respectively in `json` or `yaml` format) is equivalent to `compon #### Resources that support set-based requirements -Newer resources, such as [`Job`](/docs/concepts/jobs/run-to-completion-finite-workloads/), [`Deployment`](/docs/concepts/workloads/controllers/deployment/), [`Replica Set`](/docs/concepts/workloads/controllers/replicaset/), and [`Daemon Set`](/docs/concepts/workloads/controllers/daemonset/), support _set-based_ requirements as well. +Newer resources, such as [`Job`](/docs/concepts/workloads/controllers/jobs-run-to-completion/), [`Deployment`](/docs/concepts/workloads/controllers/deployment/), [`ReplicaSet`](/docs/concepts/workloads/controllers/replicaset/), and [`DaemonSet`](/docs/concepts/workloads/controllers/daemonset/), support _set-based_ requirements as well. ```yaml selector: diff --git a/content/en/docs/tasks/run-application/run-single-instance-stateful-application.md b/content/en/docs/tasks/run-application/run-single-instance-stateful-application.md index 87f0b01ad0..777265c68b 100644 --- a/content/en/docs/tasks/run-application/run-single-instance-stateful-application.md +++ b/content/en/docs/tasks/run-application/run-single-instance-stateful-application.md @@ -187,7 +187,7 @@ underlying resource upon deleting the PersistentVolume. * Learn more about [Deployment objects](/docs/concepts/workloads/controllers/deployment/). -* Learn more about [Deploying applications](/docs/user-guide/deploying-applications/) +* Learn more about [Deploying applications](/docs/tasks/run-application/run-stateless-application-deployment/) * [kubectl run documentation](/docs/reference/generated/kubectl/kubectl-commands/#run) diff --git a/content/en/docs/tutorials/hello-minikube.md b/content/en/docs/tutorials/hello-minikube.md index 92a465ea4f..e8a16568ad 100644 --- a/content/en/docs/tutorials/hello-minikube.md +++ b/content/en/docs/tutorials/hello-minikube.md @@ -8,7 +8,7 @@ menu: weight: 10 post: >

Ready to get your hands dirty? Build a simple Kubernetes cluster that runs "Hello World" for Node.js.

-card: +card: name: tutorials weight: 10 --- @@ -17,7 +17,7 @@ card: This tutorial shows you how to run a simple Hello World Node.js app on Kubernetes using [Minikube](/docs/setup/learning-environment/minikube) and Katacoda. -Katacoda provides a free, in-browser Kubernetes environment. +Katacoda provides a free, in-browser Kubernetes environment. {{< note >}} You can also follow this tutorial if you've installed [Minikube locally](/docs/tasks/tools/install-minikube/). @@ -49,7 +49,7 @@ For more information on the `docker build` command, read the [Docker documentati ## Create a Minikube cluster -1. Click **Launch Terminal** +1. Click **Launch Terminal** {{< kat-button >}} @@ -63,7 +63,7 @@ For more information on the `docker build` command, read the [Docker documentati 3. Katacoda environment only: At the top of the terminal pane, click the plus sign, and then click **Select port to view on Host 1**. -4. Katacoda environment only: Type `30000`, and then click **Display Port**. +4. Katacoda environment only: Type `30000`, and then click **Display Port**. ## Create a Deployment @@ -75,7 +75,7 @@ Pod and restarts the Pod's Container if it terminates. Deployments are the recommended way to manage the creation and scaling of Pods. 1. Use the `kubectl create` command to create a Deployment that manages a Pod. The -Pod runs a Container based on the provided Docker image. +Pod runs a Container based on the provided Docker image. ```shell kubectl create deployment hello-node --image=gcr.io/hello-minikube-zero-install/hello-node @@ -118,7 +118,7 @@ Pod runs a Container based on the provided Docker image. ```shell kubectl config view ``` - + {{< note >}}For more information about `kubectl`commands, see the [kubectl overview](/docs/user-guide/kubectl-overview/).{{< /note >}} ## Create a Service @@ -133,7 +133,7 @@ Kubernetes [*Service*](/docs/concepts/services-networking/service/). ```shell kubectl expose deployment hello-node --type=LoadBalancer --port=8080 ``` - + The `--type=LoadBalancer` flag indicates that you want to expose your Service outside of the cluster. @@ -199,13 +199,13 @@ Minikube has a set of built-in {{< glossary_tooltip text="addons" term_id="addon storage-provisioner: enabled storage-provisioner-gluster: disabled ``` - + 2. Enable an addon, for example, `metrics-server`: ```shell minikube addons enable metrics-server ``` - + The output is similar to: ``` @@ -246,7 +246,7 @@ Minikube has a set of built-in {{< glossary_tooltip text="addons" term_id="addon ```shell minikube addons disable metrics-server ``` - + The output is similar to: ``` @@ -279,7 +279,7 @@ minikube delete {{% capture whatsnext %}} * Learn more about [Deployment objects](/docs/concepts/workloads/controllers/deployment/). -* Learn more about [Deploying applications](/docs/user-guide/deploying-applications/). +* Learn more about [Deploying applications](/docs/tasks/run-application/run-stateless-application-deployment/). * Learn more about [Service objects](/docs/concepts/services-networking/service/). {{% /capture %}} From 2faf1024d944db2a1e9efeb88ada1dcf3f0f9ea2 Mon Sep 17 00:00:00 2001 From: Tim Bannister Date: Tue, 11 Feb 2020 03:24:01 +0000 Subject: [PATCH 005/111] Tweak linking for Kubernetes object concept (#18122) - Add a link from /docs/reference/using-api/api-concepts/ - Tweak other incoming links to match --- content/en/docs/concepts/_index.md | 6 +++--- .../en/docs/concepts/architecture/controller.md | 2 +- .../api-extension/custom-resources.md | 2 +- .../working-with-objects/kubernetes-objects.md | 17 +++++++++-------- .../en/docs/reference/using-api/api-concepts.md | 2 +- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/content/en/docs/concepts/_index.md b/content/en/docs/concepts/_index.md index 2106ae21cb..0cb970fd66 100644 --- a/content/en/docs/concepts/_index.md +++ b/content/en/docs/concepts/_index.md @@ -24,9 +24,9 @@ Once you've set your desired state, the *Kubernetes Control Plane* makes the clu * **[kubelet](/docs/admin/kubelet/)**, which communicates with the Kubernetes Master. * **[kube-proxy](/docs/admin/kube-proxy/)**, a network proxy which reflects Kubernetes networking services on each node. -## Kubernetes Objects +## Kubernetes objects -Kubernetes contains a number of abstractions that represent the state of your system: deployed containerized applications and workloads, their associated network and disk resources, and other information about what your cluster is doing. These abstractions are represented by objects in the Kubernetes API. See [Understanding Kubernetes Objects](/docs/concepts/overview/working-with-objects/kubernetes-objects/) for more details. +Kubernetes contains a number of abstractions that represent the state of your system: deployed containerized applications and workloads, their associated network and disk resources, and other information about what your cluster is doing. These abstractions are represented by objects in the Kubernetes API. See [Understanding Kubernetes objects](/docs/concepts/overview/working-with-objects/kubernetes-objects/#kubernetes-objects) for more details. The basic Kubernetes objects include: @@ -35,7 +35,7 @@ The basic Kubernetes objects include: * [Volume](/docs/concepts/storage/volumes/) * [Namespace](/docs/concepts/overview/working-with-objects/namespaces/) -Kubernetes also contains higher-level abstractions that rely on [Controllers](/docs/concepts/architecture/controller/) to build upon the basic objects, and provide additional functionality and convenience features. These include: +Kubernetes also contains higher-level abstractions that rely on [controllers](/docs/concepts/architecture/controller/) to build upon the basic objects, and provide additional functionality and convenience features. These include: * [Deployment](/docs/concepts/workloads/controllers/deployment/) * [DaemonSet](/docs/concepts/workloads/controllers/daemonset/) diff --git a/content/en/docs/concepts/architecture/controller.md b/content/en/docs/concepts/architecture/controller.md index fe8965f3e2..e5bee1d0a5 100644 --- a/content/en/docs/concepts/architecture/controller.md +++ b/content/en/docs/concepts/architecture/controller.md @@ -26,7 +26,7 @@ closer to the desired state, by turning equipment on or off. ## Controller pattern A controller tracks at least one Kubernetes resource type. -These [objects](/docs/concepts/overview/working-with-objects/kubernetes-objects/) +These [objects](/docs/concepts/overview/working-with-objects/kubernetes-objects/#kubernetes-objects) have a spec field that represents the desired state. The controller(s) for that resource are responsible for making the current state come closer to that desired state. diff --git a/content/en/docs/concepts/extend-kubernetes/api-extension/custom-resources.md b/content/en/docs/concepts/extend-kubernetes/api-extension/custom-resources.md index 4d3da6ad11..660d589169 100644 --- a/content/en/docs/concepts/extend-kubernetes/api-extension/custom-resources.md +++ b/content/en/docs/concepts/extend-kubernetes/api-extension/custom-resources.md @@ -37,7 +37,7 @@ On their own, custom resources simply let you store and retrieve structured data When you combine a custom resource with a *custom controller*, custom resources provide a true _declarative API_. -A [declarative API](/docs/concepts/overview/working-with-objects/kubernetes-objects/#understanding-kubernetes-objects) +A [declarative API](/docs/concepts/overview/kubernetes-api/) allows you to _declare_ or specify the desired state of your resource and tries to keep the current state of Kubernetes objects in sync with the desired state. The controller interprets the structured data as a record of the user's diff --git a/content/en/docs/concepts/overview/working-with-objects/kubernetes-objects.md b/content/en/docs/concepts/overview/working-with-objects/kubernetes-objects.md index f0bac7e4cb..b6c09be817 100644 --- a/content/en/docs/concepts/overview/working-with-objects/kubernetes-objects.md +++ b/content/en/docs/concepts/overview/working-with-objects/kubernetes-objects.md @@ -12,9 +12,9 @@ This page explains how Kubernetes objects are represented in the Kubernetes API, {{% /capture %}} {{% capture body %}} -## Understanding Kubernetes Objects +## Understanding Kubernetes objects {#kubernetes-objects} -*Kubernetes Objects* are persistent entities in the Kubernetes system. Kubernetes uses these entities to represent the state of your cluster. Specifically, they can describe: +*Kubernetes objects* are persistent entities in the Kubernetes system. Kubernetes uses these entities to represent the state of your cluster. Specifically, they can describe: * What containerized applications are running (and on which nodes) * The resources available to those applications @@ -33,7 +33,7 @@ For example, a Kubernetes Deployment is an object that can represent an applicat For more information on the object spec, status, and metadata, see the [Kubernetes API Conventions](https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md). -### Describing a Kubernetes Object +### Describing a Kubernetes object When you create an object in Kubernetes, you must provide the object spec that describes its desired state, as well as some basic information about the object (such as a name). When you use the Kubernetes API to create the object (either directly or via `kubectl`), that API request must include that information as JSON in the request body. **Most often, you provide the information to `kubectl` in a .yaml file.** `kubectl` converts the information to JSON when making the API request. @@ -51,7 +51,7 @@ kubectl apply -f https://k8s.io/examples/application/deployment.yaml --record The output is similar to this: -```shell +``` deployment.apps/nginx-deployment created ``` @@ -65,14 +65,15 @@ In the `.yaml` file for the Kubernetes object you want to create, you'll need to * `spec` - What state you desire for the object The precise format of the object `spec` is different for every Kubernetes object, and contains nested fields specific to that object. The [Kubernetes API Reference](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/) can help you find the spec format for all of the objects you can create using Kubernetes. -For example, the `spec` format for a `Pod` can be found -[here](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#podspec-v1-core), -and the `spec` format for a `Deployment` can be found -[here](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#deploymentspec-v1-apps). +For example, the `spec` format for a Pod can be found in +[PodSpec v1 core](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#podspec-v1-core), +and the `spec` format for a Deployment can be found +[DeploymentSpec v1 apps](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#deploymentspec-v1-apps). {{% /capture %}} {{% capture whatsnext %}} +* [Kubernetes API overview](/docs/reference/using-api/api-overview/) explains some more API concepts * Learn about the most important basic Kubernetes objects, such as [Pod](/docs/concepts/workloads/pods/pod-overview/). * Learn about [controllers](/docs/concepts/architecture/controller/) in Kubernetes {{% /capture %}} diff --git a/content/en/docs/reference/using-api/api-concepts.md b/content/en/docs/reference/using-api/api-concepts.md index 8b82d7da26..e30de75330 100644 --- a/content/en/docs/reference/using-api/api-concepts.md +++ b/content/en/docs/reference/using-api/api-concepts.md @@ -18,7 +18,7 @@ updating, and deleting primary resources via the standard HTTP verbs (POST, PUT, ## Standard API terminology -Most Kubernetes API resource types are "objects" - they represent a concrete instance of a concept on the cluster, like a pod or namespace. A smaller number of API resource types are "virtual" - they often represent operations rather than objects, such as a permission check (use a POST with a JSON-encoded body of `SubjectAccessReview` to the `subjectaccessreviews` resource). All objects will have a unique name to allow idempotent creation and retrieval, but virtual resource types may not have unique names if they are not retrievable or do not rely on idempotency. +Most Kubernetes API resource types are [objects](/docs/concepts/overview/working-with-objects/kubernetes-objects/#kubernetes-objects): they represent a concrete instance of a concept on the cluster, like a pod or namespace. A smaller number of API resource types are "virtual" - they often represent operations rather than objects, such as a permission check (use a POST with a JSON-encoded body of `SubjectAccessReview` to the `subjectaccessreviews` resource). All objects will have a unique name to allow idempotent creation and retrieval, but virtual resource types may not have unique names if they are not retrievable or do not rely on idempotency. Kubernetes generally leverages standard RESTful terminology to describe the API concepts: From b550c6c05178a4b25084022051b25ca176402da2 Mon Sep 17 00:00:00 2001 From: Qiming Teng Date: Tue, 11 Feb 2020 11:52:00 +0800 Subject: [PATCH 006/111] Remove shortcode 'code' (#19035) A long time ago, we added a new shortcode `codenew` as a replacement of the `code` shortcode. The intention was to consolidate all example manifests to a single subdirectory, i.e. `content//examples`. Now this transition is almost over. We have only two instances where the old `code` shortcode is referenced. This PR makes the `policy.rego` file inlined content so that all referenes to `code` are killed. We can safely drop the `code` shortcode. If desired, we can rename the `codenew` shortcode to `code` in a (series of) separate PR(s). --- content/en/docs/tasks/federation/policy.rego | 74 ------------------ .../set-up-placement-policies-federation.md | 77 ++++++++++++++++++- content/zh/docs/tasks/federation/policy.rego | 74 ------------------ .../set-up-placement-policies-federation.md | 77 ++++++++++++++++++- layouts/shortcodes/code.html | 38 --------- 5 files changed, 152 insertions(+), 188 deletions(-) delete mode 100644 content/en/docs/tasks/federation/policy.rego delete mode 100644 content/zh/docs/tasks/federation/policy.rego delete mode 100644 layouts/shortcodes/code.html diff --git a/content/en/docs/tasks/federation/policy.rego b/content/en/docs/tasks/federation/policy.rego deleted file mode 100644 index 49827b6ae9..0000000000 --- a/content/en/docs/tasks/federation/policy.rego +++ /dev/null @@ -1,74 +0,0 @@ -# OPA supports a high-level declarative language named Rego for authoring and -# enforcing policies. For more information on Rego, visit -# http://openpolicyagent.org. - -# Rego policies are namespaced by the "package" directive. -package kubernetes.placement - -# Imports provide aliases for data inside the policy engine. In this case, the -# policy simply refers to "clusters" below. -import data.kubernetes.clusters - -# The "annotations" rule generates a JSON object containing the key -# "federation.kubernetes.io/replica-set-preferences" mapped to . -# The preferences values is generated dynamically by OPA when it evaluates the -# rule. -# -# The SchedulingPolicy Admission Controller running inside the Federation API -# server will merge these annotations into incoming Federated resources. By -# setting replica-set-preferences, we can control the placement of Federated -# ReplicaSets. -# -# Rules are defined to generate JSON values (booleans, strings, objects, etc.) -# When OPA evaluates a rule, it generates a value IF all of the expressions in -# the body evaluate successfully. All rules can be understood intuitively as -# if where is true if AND AND ... -# is true (for some set of data.) -annotations["federation.kubernetes.io/replica-set-preferences"] = preferences { - input.kind = "ReplicaSet" - value = {"clusters": cluster_map, "rebalance": true} - json.marshal(value, preferences) -} - -# This "annotations" rule generates a value for the "federation.alpha.kubernetes.io/cluster-selector" -# annotation. -# -# In English, the policy asserts that resources in the "production" namespace -# that are not annotated with "criticality=low" MUST be placed on clusters -# labelled with "on-premises=true". -annotations["federation.alpha.kubernetes.io/cluster-selector"] = selector { - input.metadata.namespace = "production" - not input.metadata.annotations.criticality = "low" - json.marshal([{ - "operator": "=", - "key": "on-premises", - "values": "[true]", - }], selector) -} - -# Generates a set of cluster names that satisfy the incoming Federated -# ReplicaSet's requirements. In this case, just PCI compliance. -replica_set_clusters[cluster_name] { - clusters[cluster_name] - not insufficient_pci[cluster_name] -} - -# Generates a set of clusters that must not be used for Federated ReplicaSets -# that request PCI compliance. -insufficient_pci[cluster_name] { - clusters[cluster_name] - input.metadata.annotations["requires-pci"] = "true" - not pci_clusters[cluster_name] -} - -# Generates a set of clusters that are PCI certified. In this case, we assume -# clusters are annotated to indicate if they have passed PCI compliance audits. -pci_clusters[cluster_name] { - clusters[cluster_name].metadata.annotations["pci-certified"] = "true" -} - -# Helper rule to generate a mapping of desired clusters to weights. In this -# case, weights are static. -cluster_map[cluster_name] = {"weight": 1} { - replica_set_clusters[cluster_name] -} diff --git a/content/en/docs/tasks/federation/set-up-placement-policies-federation.md b/content/en/docs/tasks/federation/set-up-placement-policies-federation.md index 4329245d95..d7ac469ea9 100644 --- a/content/en/docs/tasks/federation/set-up-placement-policies-federation.md +++ b/content/en/docs/tasks/federation/set-up-placement-policies-federation.md @@ -108,7 +108,82 @@ Create the namespace if it does not already exist: Configure a sample policy to test the external policy engine: -{{< code file="policy.rego" >}} +``` +# OPA supports a high-level declarative language named Rego for authoring and +# enforcing policies. For more information on Rego, visit +# http://openpolicyagent.org. + +# Rego policies are namespaced by the "package" directive. +package kubernetes.placement + +# Imports provide aliases for data inside the policy engine. In this case, the +# policy simply refers to "clusters" below. +import data.kubernetes.clusters + +# The "annotations" rule generates a JSON object containing the key +# "federation.kubernetes.io/replica-set-preferences" mapped to . +# The preferences values is generated dynamically by OPA when it evaluates the +# rule. +# +# The SchedulingPolicy Admission Controller running inside the Federation API +# server will merge these annotations into incoming Federated resources. By +# setting replica-set-preferences, we can control the placement of Federated +# ReplicaSets. +# +# Rules are defined to generate JSON values (booleans, strings, objects, etc.) +# When OPA evaluates a rule, it generates a value IF all of the expressions in +# the body evaluate successfully. All rules can be understood intuitively as +# if where is true if AND AND ... +# is true (for some set of data.) +annotations["federation.kubernetes.io/replica-set-preferences"] = preferences { + input.kind = "ReplicaSet" + value = {"clusters": cluster_map, "rebalance": true} + json.marshal(value, preferences) +} + +# This "annotations" rule generates a value for the "federation.alpha.kubernetes.io/cluster-selector" +# annotation. +# +# In English, the policy asserts that resources in the "production" namespace +# that are not annotated with "criticality=low" MUST be placed on clusters +# labelled with "on-premises=true". +annotations["federation.alpha.kubernetes.io/cluster-selector"] = selector { + input.metadata.namespace = "production" + not input.metadata.annotations.criticality = "low" + json.marshal([{ + "operator": "=", + "key": "on-premises", + "values": "[true]", + }], selector) +} + +# Generates a set of cluster names that satisfy the incoming Federated +# ReplicaSet's requirements. In this case, just PCI compliance. +replica_set_clusters[cluster_name] { + clusters[cluster_name] + not insufficient_pci[cluster_name] +} + +# Generates a set of clusters that must not be used for Federated ReplicaSets +# that request PCI compliance. +insufficient_pci[cluster_name] { + clusters[cluster_name] + input.metadata.annotations["requires-pci"] = "true" + not pci_clusters[cluster_name] +} + +# Generates a set of clusters that are PCI certified. In this case, we assume +# clusters are annotated to indicate if they have passed PCI compliance audits. +pci_clusters[cluster_name] { + clusters[cluster_name].metadata.annotations["pci-certified"] = "true" +} + +# Helper rule to generate a mapping of desired clusters to weights. In this +# case, weights are static. +cluster_map[cluster_name] = {"weight": 1} { + replica_set_clusters[cluster_name] +} +``` Shown below is the command to create the sample policy: diff --git a/content/zh/docs/tasks/federation/policy.rego b/content/zh/docs/tasks/federation/policy.rego deleted file mode 100644 index 49827b6ae9..0000000000 --- a/content/zh/docs/tasks/federation/policy.rego +++ /dev/null @@ -1,74 +0,0 @@ -# OPA supports a high-level declarative language named Rego for authoring and -# enforcing policies. For more information on Rego, visit -# http://openpolicyagent.org. - -# Rego policies are namespaced by the "package" directive. -package kubernetes.placement - -# Imports provide aliases for data inside the policy engine. In this case, the -# policy simply refers to "clusters" below. -import data.kubernetes.clusters - -# The "annotations" rule generates a JSON object containing the key -# "federation.kubernetes.io/replica-set-preferences" mapped to . -# The preferences values is generated dynamically by OPA when it evaluates the -# rule. -# -# The SchedulingPolicy Admission Controller running inside the Federation API -# server will merge these annotations into incoming Federated resources. By -# setting replica-set-preferences, we can control the placement of Federated -# ReplicaSets. -# -# Rules are defined to generate JSON values (booleans, strings, objects, etc.) -# When OPA evaluates a rule, it generates a value IF all of the expressions in -# the body evaluate successfully. All rules can be understood intuitively as -# if where is true if AND AND ... -# is true (for some set of data.) -annotations["federation.kubernetes.io/replica-set-preferences"] = preferences { - input.kind = "ReplicaSet" - value = {"clusters": cluster_map, "rebalance": true} - json.marshal(value, preferences) -} - -# This "annotations" rule generates a value for the "federation.alpha.kubernetes.io/cluster-selector" -# annotation. -# -# In English, the policy asserts that resources in the "production" namespace -# that are not annotated with "criticality=low" MUST be placed on clusters -# labelled with "on-premises=true". -annotations["federation.alpha.kubernetes.io/cluster-selector"] = selector { - input.metadata.namespace = "production" - not input.metadata.annotations.criticality = "low" - json.marshal([{ - "operator": "=", - "key": "on-premises", - "values": "[true]", - }], selector) -} - -# Generates a set of cluster names that satisfy the incoming Federated -# ReplicaSet's requirements. In this case, just PCI compliance. -replica_set_clusters[cluster_name] { - clusters[cluster_name] - not insufficient_pci[cluster_name] -} - -# Generates a set of clusters that must not be used for Federated ReplicaSets -# that request PCI compliance. -insufficient_pci[cluster_name] { - clusters[cluster_name] - input.metadata.annotations["requires-pci"] = "true" - not pci_clusters[cluster_name] -} - -# Generates a set of clusters that are PCI certified. In this case, we assume -# clusters are annotated to indicate if they have passed PCI compliance audits. -pci_clusters[cluster_name] { - clusters[cluster_name].metadata.annotations["pci-certified"] = "true" -} - -# Helper rule to generate a mapping of desired clusters to weights. In this -# case, weights are static. -cluster_map[cluster_name] = {"weight": 1} { - replica_set_clusters[cluster_name] -} diff --git a/content/zh/docs/tasks/federation/set-up-placement-policies-federation.md b/content/zh/docs/tasks/federation/set-up-placement-policies-federation.md index b56d43e83b..774966f39c 100644 --- a/content/zh/docs/tasks/federation/set-up-placement-policies-federation.md +++ b/content/zh/docs/tasks/federation/set-up-placement-policies-federation.md @@ -188,7 +188,82 @@ Configure a sample policy to test the external policy engine: --> 配置一个示例策略来测试外部策略引擎: -{{< code file="policy.rego" >}} +``` +# OPA supports a high-level declarative language named Rego for authoring and +# enforcing policies. For more information on Rego, visit +# http://openpolicyagent.org. + +# Rego policies are namespaced by the "package" directive. +package kubernetes.placement + +# Imports provide aliases for data inside the policy engine. In this case, the +# policy simply refers to "clusters" below. +import data.kubernetes.clusters + +# The "annotations" rule generates a JSON object containing the key +# "federation.kubernetes.io/replica-set-preferences" mapped to . +# The preferences values is generated dynamically by OPA when it evaluates the +# rule. +# +# The SchedulingPolicy Admission Controller running inside the Federation API +# server will merge these annotations into incoming Federated resources. By +# setting replica-set-preferences, we can control the placement of Federated +# ReplicaSets. +# +# Rules are defined to generate JSON values (booleans, strings, objects, etc.) +# When OPA evaluates a rule, it generates a value IF all of the expressions in +# the body evaluate successfully. All rules can be understood intuitively as +# if where is true if AND AND ... +# is true (for some set of data.) +annotations["federation.kubernetes.io/replica-set-preferences"] = preferences { + input.kind = "ReplicaSet" + value = {"clusters": cluster_map, "rebalance": true} + json.marshal(value, preferences) +} + +# This "annotations" rule generates a value for the "federation.alpha.kubernetes.io/cluster-selector" +# annotation. +# +# In English, the policy asserts that resources in the "production" namespace +# that are not annotated with "criticality=low" MUST be placed on clusters +# labelled with "on-premises=true". +annotations["federation.alpha.kubernetes.io/cluster-selector"] = selector { + input.metadata.namespace = "production" + not input.metadata.annotations.criticality = "low" + json.marshal([{ + "operator": "=", + "key": "on-premises", + "values": "[true]", + }], selector) +} + +# Generates a set of cluster names that satisfy the incoming Federated +# ReplicaSet's requirements. In this case, just PCI compliance. +replica_set_clusters[cluster_name] { + clusters[cluster_name] + not insufficient_pci[cluster_name] +} + +# Generates a set of clusters that must not be used for Federated ReplicaSets +# that request PCI compliance. +insufficient_pci[cluster_name] { + clusters[cluster_name] + input.metadata.annotations["requires-pci"] = "true" + not pci_clusters[cluster_name] +} + +# Generates a set of clusters that are PCI certified. In this case, we assume +# clusters are annotated to indicate if they have passed PCI compliance audits. +pci_clusters[cluster_name] { + clusters[cluster_name].metadata.annotations["pci-certified"] = "true" +} + +# Helper rule to generate a mapping of desired clusters to weights. In this +# case, weights are static. +cluster_map[cluster_name] = {"weight": 1} { + replica_set_clusters[cluster_name] +} +``` * `selector` 字段定义 Deployment 如何查找要管理的 Pods。 在这种情况下,只需选择在 Pod 模板(`app: nginx`)中定义的标签。但是,更复杂的选择规则是可能的,只要 Pod 模板本身满足规则。 - {{< note >}} + +{{< note >}} + `matchLabels` 字段是 {key,value} 的映射。单个 {key,value}在 `matchLabels` 映射中的值等效于 `matchExpressions` 的元素,其键字段是“key”,运算符为“In”,值数组仅包含“value”。所有要求,从 `matchLabels` 和 `matchExpressions`,必须满足才能匹配。 - {{< /note >}} +{{< /note >}} 1. 通过运行以下命令创建 Deployment : - {{< note >}} - 可以指定 `--record` 标志来写入在资源注释`kubernetes.io/change-cause`中执行的命令。它对以后的检查是有用的。 - 例如,查看在每个 Deployment 修改中执行的命令。 - {{< /note >}} +{{< /note >}} ```shell kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml @@ -210,10 +212,12 @@ The following is an example of a Deployment. It creates a ReplicaSet to bring up 2. Run `kubectl get deployments` to check if the Deployment was created. If the Deployment is still being created, the output is similar to the following: --> 2. 运行 `kubectl get deployments` 以检查 Deployment 是否已创建。如果仍在创建 Deployment ,则输出以下内容: + ```shell NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx-deployment 3 0 0 0 1s ``` + @@ -243,6 +247,7 @@ The following is an example of a Deployment. It creates a ReplicaSet to bring up 3. To see the Deployment rollout status, run `kubectl rollout status deployment.v1.apps/nginx-deployment`. The output is similar to this: --> 3. 要查看 Deployment 展开状态,运行 `kubectl rollout status deployment.v1.apps/nginx-deployment`。输出: + ```shell Waiting for rollout to finish: 2 out of 3 new replicas have been updated... deployment.apps/nginx-deployment successfully rolled out @@ -252,6 +257,7 @@ The following is an example of a Deployment. It creates a ReplicaSet to bring up 4. Run the `kubectl get deployments` again a few seconds later. The output is similar to this: --> 4. 几秒钟后再次运行 `kubectl get deployments`。输出: + ```shell NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx-deployment 3 3 3 3 18s @@ -265,6 +271,7 @@ The following is an example of a Deployment. It creates a ReplicaSet to bring up 5. To see the ReplicaSet (`rs`) created by the Deployment, run `kubectl get rs`. The output is similar to this: --> 5. 要查看 Deployment 创建的 ReplicaSet (`rs`),运行 `kubectl get rs`。输出: + ```shell NAME DESIRED CURRENT READY AGE nginx-deployment-75675f5897 3 3 3 18s @@ -279,6 +286,7 @@ The following is an example of a Deployment. It creates a ReplicaSet to bring up 6. To see the labels automatically generated for each Pod, run `kubectl get pods --show-labels`. The following output is returned: --> 6. 要查看每个 Pod 自动生成的标签,运行 `kubectl get pods --show-labels`。返回以下输出: + ```shell NAME READY STATUS RESTARTS AGE LABELS nginx-deployment-75675f5897-7ci7o 1/1 Running 0 18s app=nginx,pod-template-hash=3123191453 @@ -291,13 +299,13 @@ The following is an example of a Deployment. It creates a ReplicaSet to bring up --> 创建的复制集可确保有三个 `nginx` Pods。 - {{< note >}} +{{< note >}} 必须在 Deployment 中指定适当的选择器和 Pod 模板标签(在本例中为`app: nginx`)。不要与其他控制器(包括其他 Deployments 和状态设置)重叠标签或选择器。Kubernetes 不会阻止重叠,如果多个控制器具有重叠的选择器,这些控制器可能会冲突并运行意外。 - {{< /note >}} +{{< /note >}} -1. 让我们更新 nginx Pods,以使用 `nginx:1.9.1` 镜像 ,而不是 `nginx:1.7.9` 镜像 。 + 1. 让我们更新 nginx Pods,以使用 `nginx:1.9.1` 镜像 ,而不是 `nginx:1.7.9` 镜像 。 ```shell kubectl --record deployment.apps/nginx-deployment set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1 ``` + 输出: - ``` + + ```shell deployment.apps/nginx-deployment image updated ``` @@ -368,15 +378,17 @@ is changed, for example if the labels or container images of the template are up + 输出: - ``` + + ```shell deployment.apps/nginx-deployment edited ``` -2. 要查看展开状态,运行: + 2. 要查看展开状态,运行: ```shell kubectl rollout status deployment.v1.apps/nginx-deployment @@ -386,14 +398,16 @@ is changed, for example if the labels or container images of the template are up The output is similar to this: --> 输出: - ``` + + ```shell Waiting for rollout to finish: 2 out of 3 new replicas have been updated... ``` 或者 - ``` + + ```shell deployment.apps/nginx-deployment successfully rolled out ``` @@ -408,7 +422,8 @@ is changed, for example if the labels or container images of the template are up --> * 在展开成功后,可以通过运行 `kubectl get deployments`来查看 Deployment 。 输出: - ``` + + ```shell NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx-deployment 3 3 3 3 36s ``` @@ -427,7 +442,8 @@ up to 3 replicas, as well as scaling down the old ReplicaSet to 0 replicas. The output is similar to this: --> 输出: - ``` + + ```shell NAME DESIRED CURRENT READY AGE nginx-deployment-1564180365 3 3 3 6s nginx-deployment-2035384211 0 0 0 36s @@ -446,7 +462,8 @@ up to 3 replicas, as well as scaling down the old ReplicaSet to 0 replicas. The output is similar to this: --> 输出: - ``` + + ```shell NAME READY STATUS RESTARTS AGE nginx-deployment-1564180365-khku8 1/1 Running 0 14s nginx-deployment-1564180365-nacti 1/1 Running 0 14s @@ -482,6 +499,7 @@ up to 3 replicas, as well as scaling down the old ReplicaSet to 0 replicas. * Get details of your Deployment: --> * 获取 Deployment 的更多信息 + ```shell kubectl describe deployments ``` @@ -489,7 +507,8 @@ up to 3 replicas, as well as scaling down the old ReplicaSet to 0 replicas. The output is similar to this: --> 输出: - ``` + + ```shell Name: nginx-deployment Namespace: default CreationTimestamp: Thu, 30 Nov 2017 10:56:25 +0000 @@ -526,7 +545,8 @@ up to 3 replicas, as well as scaling down the old ReplicaSet to 0 replicas. Normal ScalingReplicaSet 19s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 1 Normal ScalingReplicaSet 19s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 3 Normal ScalingReplicaSet 14s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 0 - ``` + ``` + * 假设在更新 Deployment 时犯了一个拼写错误,将镜像名称命名为 `nginx:1.91` 而不是 `nginx:1.9.1`: + ```shell kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.91 --record=true ``` @@ -636,7 +657,8 @@ rolled back. The output is similar to this: --> 输出: - ``` + + ```shell deployment.apps/nginx-deployment image updated ``` @@ -653,7 +675,8 @@ rolled back. The output is similar to this: --> 输出: - ``` + + ```shell Waiting for rollout to finish: 1 out of 3 new replicas have been updated... ``` @@ -670,6 +693,7 @@ rolled back. * You see that the number of old replicas --> * 查看旧 ReplicaSets : + ```shell kubectl get rs ``` @@ -678,7 +702,8 @@ rolled back. The output is similar to this: --> 输出: - ``` + + ```shell NAME DESIRED CURRENT READY AGE nginx-deployment-1564180365 3 3 3 25s nginx-deployment-2035384211 0 0 0 36s @@ -698,7 +723,8 @@ rolled back. The output is similar to this: --> 输出: - ``` + + ```shell NAME READY STATUS RESTARTS AGE nginx-deployment-1564180365-70iae 1/1 Running 0 25s nginx-deployment-1564180365-jbqqo 1/1 Running 0 25s @@ -706,19 +732,20 @@ rolled back. nginx-deployment-3066724191-08mng 0/1 ImagePullBackOff 0 6s ``` - {{< note >}} +{{< note >}} Deployment 控制器自动停止不良展开,并停止向上扩展新的 ReplicaSet 。这取决于指定的滚动更新参数(具体为 `maxUnavailable`)。默认情况下,Kubernetes 将值设置为 25%。 - {{< /note >}} +{{< /note >}} * 获取 Deployment 描述信息: + ```shell kubectl describe deployment ``` @@ -727,7 +754,8 @@ rolled back. The output is similar to this: --> 输出: - ``` + + ```shell Name: nginx-deployment Namespace: default CreationTimestamp: Tue, 15 Mar 2016 14:48:04 -0700 @@ -785,7 +813,8 @@ rolled back. -1. 首先,检查 Deployment 修改历史: + 1. 首先,检查 Deployment 修改历史: + ```shell kubectl rollout history deployment.v1.apps/nginx-deployment ``` @@ -793,7 +822,8 @@ rolled back. The output is similar to this: --> 输出: - ``` + + ```shell deployments "nginx-deployment" REVISION CHANGE-CAUSE 1 kubectl apply --filename=https://k8s.io/examples/controllers/nginx-deployment.yaml --record=true @@ -818,7 +848,8 @@ rolled back. -2. 查看修改历史的详细信息,运行: + 2. 查看修改历史的详细信息,运行: + ```shell kubectl rollout history deployment.v1.apps/nginx-deployment --revision=2 ``` @@ -827,7 +858,8 @@ rolled back. The output is similar to this: --> 输出: - ``` + + ```shell deployments "nginx-deployment" revision 2 Labels: app=nginx pod-template-hash=1159050644 @@ -854,7 +886,8 @@ Follow the steps given below to rollback the Deployment from the current version -1. 现在已决定撤消当前展开并回滚到以前的版本: + 1. 现在已决定撤消当前展开并回滚到以前的版本: + ```shell kubectl rollout undo deployment.v1.apps/nginx-deployment ``` @@ -863,7 +896,8 @@ Follow the steps given below to rollback the Deployment from the current version The output is similar to this: --> 输出: - ``` + + ```shell deployment.apps/nginx-deployment ``` 输出: - ``` + + ```shell deployment.apps/nginx-deployment ``` @@ -897,7 +932,8 @@ Follow the steps given below to rollback the Deployment from the current version -2. 检查回滚是否成功、 Deployment 是否正在运行,运行: + 2. 检查回滚是否成功、 Deployment 是否正在运行,运行: + ```shell kubectl get deployment nginx-deployment ``` @@ -906,7 +942,8 @@ Follow the steps given below to rollback the Deployment from the current version The output is similar to this: --> 输出: - ``` + + ```shell NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx-deployment 3 3 3 3 30m ``` @@ -914,15 +951,18 @@ Follow the steps given below to rollback the Deployment from the current version -3. 获取 Deployment 描述信息: + 3. 获取 Deployment 描述信息: + ```shell kubectl describe deployment nginx-deployment ``` + 输出: - ``` + + ```shell Name: nginx-deployment Namespace: default CreationTimestamp: Sun, 02 Sep 2018 18:17:55 -0500 @@ -985,7 +1025,8 @@ kubectl scale deployment.v1.apps/nginx-deployment --replicas=10 The output is similar to this: --> 输出: -``` + +```shell deployment.apps/nginx-deployment scaled ``` @@ -1005,7 +1046,8 @@ kubectl autoscale deployment.v1.apps/nginx-deployment --min=10 --max=15 --cpu-pe The output is similar to this: --> 输出: -``` + +```shell deployment.apps/nginx-deployment scaled ``` @@ -1031,6 +1073,7 @@ ReplicaSets (ReplicaSets with Pods) in order to mitigate risk. This is called *p * Ensure that the 10 replicas in your Deployment are running. --> * 确保这10个副本都在运行。 + ```shell kubectl get deploy ``` @@ -1040,7 +1083,7 @@ ReplicaSets (ReplicaSets with Pods) in order to mitigate risk. This is called *p --> 输出: - ``` + ```shell NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx-deployment 10 10 10 10 50s ``` @@ -1049,6 +1092,7 @@ ReplicaSets (ReplicaSets with Pods) in order to mitigate risk. This is called *p * You update to a new image which happens to be unresolvable from inside the cluster. --> * 更新到新镜像,该镜像恰好无法从集群内部解析。 + ```shell kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:sometag ``` @@ -1057,7 +1101,8 @@ ReplicaSets (ReplicaSets with Pods) in order to mitigate risk. This is called *p The output is similar to this: --> 输出: - ``` + + ```shell deployment.apps/nginx-deployment image updated ``` @@ -1066,6 +1111,7 @@ ReplicaSets (ReplicaSets with Pods) in order to mitigate risk. This is called *p `maxUnavailable` requirement that you mentioned above. Check out the rollout status: --> * 镜像更新使用 ReplicaSet nginx-deployment-1989198191 启动新的展开,但由于上面提到的最大不可用要求。检查展开状态: + ```shell kubectl get rs ``` @@ -1073,7 +1119,8 @@ ReplicaSets (ReplicaSets with Pods) in order to mitigate risk. This is called *p The output is similar to this: --> 输出: - ``` + + ```shell NAME DESIRED CURRENT READY AGE nginx-deployment-1989198191 5 5 0 9s nginx-deployment-618515232 8 8 8 1m @@ -1104,7 +1151,8 @@ kubectl get deploy The output is similar to this: --> 输出: -``` + +```shell NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx-deployment 15 18 7 8 7m ``` @@ -1113,6 +1161,7 @@ nginx-deployment 15 18 7 8 7m The rollout status confirms how the replicas were added to each ReplicaSet. --> 展开状态确认副本如何添加到每个 ReplicaSet 。 + ```shell kubectl get rs ``` @@ -1121,7 +1170,8 @@ kubectl get rs The output is similar to this: --> 输出: -``` + +```shell NAME DESIRED CURRENT READY AGE nginx-deployment-1989198191 7 7 0 7m nginx-deployment-618515232 11 11 11 7m @@ -1144,6 +1194,7 @@ apply multiple fixes in between pausing and resuming without triggering unnecess --> * 例如,对于一个刚刚创建的 Deployment : 获取 Deployment 信息: + ```shell kubectl get deploy ``` @@ -1151,7 +1202,8 @@ apply multiple fixes in between pausing and resuming without triggering unnecess The output is similar to this: --> 输出: - ``` + + ```shell NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx 3 3 3 3 1m ``` @@ -1160,6 +1212,7 @@ apply multiple fixes in between pausing and resuming without triggering unnecess Get the rollout status: --> 获取 Deployment 状态: + ```shell kubectl get rs ``` @@ -1168,7 +1221,8 @@ apply multiple fixes in between pausing and resuming without triggering unnecess The output is similar to this: --> 输出: - ``` + + ```shell NAME DESIRED CURRENT READY AGE nginx-2142116321 3 3 3 1m ``` @@ -1177,6 +1231,7 @@ apply multiple fixes in between pausing and resuming without triggering unnecess * Pause by running the following command: --> 使用如下指令中断运行: + ```shell kubectl rollout pause deployment.v1.apps/nginx-deployment ``` @@ -1185,7 +1240,8 @@ apply multiple fixes in between pausing and resuming without triggering unnecess The output is similar to this: --> 输出: - ``` + + ```shell deployment.apps/nginx-deployment paused ``` @@ -1193,6 +1249,7 @@ apply multiple fixes in between pausing and resuming without triggering unnecess * Then update the image of the Deployment: --> * 然后更新 Deployment 镜像: + ```shell kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1 ``` @@ -1201,7 +1258,8 @@ apply multiple fixes in between pausing and resuming without triggering unnecess The output is similar to this: --> 输出: - ``` + + ```shell deployment.apps/nginx-deployment image updated ``` @@ -1209,6 +1267,7 @@ apply multiple fixes in between pausing and resuming without triggering unnecess * Notice that no new rollout started: --> * 注意没有新的展开: + ```shell kubectl rollout history deployment.v1.apps/nginx-deployment ``` @@ -1217,7 +1276,8 @@ apply multiple fixes in between pausing and resuming without triggering unnecess The output is similar to this: --> 输出: - ``` + + ```shell deployments "nginx" REVISION CHANGE-CAUSE 1 @@ -1227,6 +1287,7 @@ apply multiple fixes in between pausing and resuming without triggering unnecess * Get the rollout status to ensure that the Deployment is updates successfully: --> * 获取展开状态确保 Deployment 更新已经成功: + ```shell kubectl get rs ``` @@ -1235,7 +1296,8 @@ apply multiple fixes in between pausing and resuming without triggering unnecess The output is similar to this: --> 输出: - ``` + + ```shell NAME DESIRED CURRENT READY AGE nginx-2142116321 3 3 3 2m ``` @@ -1244,6 +1306,7 @@ apply multiple fixes in between pausing and resuming without triggering unnecess * You can make as many updates as you wish, for example, update the resources that will be used: --> * 更新是很容易的,例如,可以这样更新使用到的资源: + ```shell kubectl set resources deployment.v1.apps/nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi ``` @@ -1252,7 +1315,8 @@ apply multiple fixes in between pausing and resuming without triggering unnecess The output is similar to this: --> 输出: - ``` + + ```shell deployment.apps/nginx-deployment resource requirements updated ``` @@ -1266,6 +1330,7 @@ apply multiple fixes in between pausing and resuming without triggering unnecess * Eventually, resume the Deployment and observe a new ReplicaSet coming up with all the new updates: --> * 最后,恢复 Deployment 并观察新的 ReplicaSet ,并更新所有新的更新: + ```shell kubectl rollout resume deployment.v1.apps/nginx-deployment ``` @@ -1274,13 +1339,15 @@ apply multiple fixes in between pausing and resuming without triggering unnecess The output is similar to this: --> 输出: - ``` + + ```shell deployment.apps/nginx-deployment resumed ``` * 观察展开的状态,直到完成。 + ```shell kubectl get rs -w ``` @@ -1289,7 +1356,8 @@ apply multiple fixes in between pausing and resuming without triggering unnecess The output is similar to this: --> 输出: - ``` + + ```shell NAME DESIRED CURRENT READY AGE nginx-2142116321 2 2 2 2m nginx-3926361531 2 2 0 6s @@ -1311,6 +1379,7 @@ apply multiple fixes in between pausing and resuming without triggering unnecess * Get the status of the latest rollout: --> * 获取最近展开的状态: + ```shell kubectl get rs ``` @@ -1319,11 +1388,13 @@ apply multiple fixes in between pausing and resuming without triggering unnecess The output is similar to this: --> 输出: - ``` + + ```shell NAME DESIRED CURRENT READY AGE nginx-2142116321 0 0 0 2m nginx-3926361531 3 3 3 28s ``` + {{< note >}} 输出: -``` + +```shell Waiting for rollout to finish: 2 of 3 updated replicas are available... deployment.apps/nginx-deployment successfully rolled out $ echo $? @@ -1463,7 +1535,8 @@ kubectl patch deployment.v1.apps/nginx-deployment -p '{"spec":{"progressDeadline The output is similar to this: --> 输出: -``` + +```shell deployment.apps/nginx-deployment patched ``` @@ -1515,7 +1588,8 @@ kubectl describe deployment nginx-deployment The output is similar to this: --> 输出: -``` + +```shell <...> Conditions: Type Status Reason @@ -1531,7 +1605,7 @@ Conditions: --> 如果运行 `kubectl get deployment nginx-deployment -o yaml`, Deployment 状态输出: -``` +```shell status: availableReplicas: 2 conditions: @@ -1565,7 +1639,7 @@ reason for the Progressing condition: --> 最终,一旦超过 Deployment 进度截止时间,Kubernetes 将更新状态和进度状态: -``` +```shell Conditions: Type Status Reason ---- ------ ------ @@ -1582,7 +1656,7 @@ Deployment's status update with a successful condition (`Status=True` and `Reaso --> 可以通过缩减 Deployment 来解决配额不足的问题,或者直接在命名空间中增加配额。如果配额条件满足, Deployment 控制器完成了 Deployment 展开, Deployment 状态会更新为成功(`Status=True` and `Reason=NewReplicaSetAvailable`)。 -``` +```shell Conditions: Type Status Reason ---- ------ ------ @@ -1612,7 +1686,8 @@ kubectl rollout status deployment.v1.apps/nginx-deployment The output is similar to this: --> 输出: -``` + +```shell Waiting for rollout to finish: 2 out of 3 new replicas have been updated... error: deployment "nginx" exceeded its progress deadline $ echo $? From 834f1c6bbe0e00840b86d9ff54cae365271381b2 Mon Sep 17 00:00:00 2001 From: Jim Angel Date: Tue, 11 Feb 2020 20:42:07 -0600 Subject: [PATCH 015/111] adding in a docs alias (#19077) --- content/en/docs/reference/access-authn-authz/rbac.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/reference/access-authn-authz/rbac.md b/content/en/docs/reference/access-authn-authz/rbac.md index 1d840c173f..852e73fd79 100644 --- a/content/en/docs/reference/access-authn-authz/rbac.md +++ b/content/en/docs/reference/access-authn-authz/rbac.md @@ -5,7 +5,7 @@ reviewers: - liggitt title: Using RBAC Authorization content_template: templates/concept -aliases: [/rbac/] +aliases: [../../../rbac/] weight: 70 --- From a48b34474a2d652584e5fca3d83c267ffe352203 Mon Sep 17 00:00:00 2001 From: Jim Angel Date: Wed, 12 Feb 2020 05:28:52 -0600 Subject: [PATCH 016/111] updating agenda meeting link (#19087) --- content/en/docs/contribute/start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/contribute/start.md b/content/en/docs/contribute/start.md index 4af5f6d5ce..acd5a5bfdf 100644 --- a/content/en/docs/contribute/start.md +++ b/content/en/docs/contribute/start.md @@ -61,7 +61,7 @@ formatting, and typographic conventions. Look over the style guide before you make your first contribution, and use it when you have questions. Changes to the style guide are made by SIG Docs as a group. To propose a change -or addition, [add it to the agenda](https://docs.google.com/document/d/1zg6By77SGg90EVUrhDIhopjZlSDg2jCebU-Ks9cYx0w/edit#) for an upcoming SIG Docs meeting, and attend the meeting to participate in the +or addition, [add it to the agenda](https://docs.google.com/document/d/1ddHwLK3kUMX1wVFIwlksjTk0MsqitBnWPe1LRa1Rx5A/edit) for an upcoming SIG Docs meeting, and attend the meeting to participate in the discussion. See the [advanced contribution](/docs/contribute/advanced/) topic for more information. From a00f65d84ca19ed7ef5c71179e2ccfb05dd64bbe Mon Sep 17 00:00:00 2001 From: larntz-tbc <60480713+larntz-tbc@users.noreply.github.com> Date: Wed, 12 Feb 2020 13:56:51 -0500 Subject: [PATCH 017/111] cri-o version must match the k8 version (#19092) * cri-o version must match the k8 version It's not clear from the doc that the cri-o version must match the k8 version as shown in the cri-o compatibility matrix. * changed to note shortcode for cri-o compat matrix - fix author --- .../docs/setup/production-environment/container-runtimes.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/content/en/docs/setup/production-environment/container-runtimes.md b/content/en/docs/setup/production-environment/container-runtimes.md index 704a2728c5..493e2ae5ef 100644 --- a/content/en/docs/setup/production-environment/container-runtimes.md +++ b/content/en/docs/setup/production-environment/container-runtimes.md @@ -162,6 +162,11 @@ This section contains the necessary steps to install `CRI-O` as CRI runtime. Use the following commands to install CRI-O on your system: +{{< note >}} +The CRI-O major and minor versions must match the Kubernetes major and minor versions. +For more information, see the [CRI-O compatiblity matrix](https://github.com/cri-o/cri-o). +{{< /note >}} + ### Prerequisites ```shell From c8eb9126e93297b35061bb97a8430e437e5048b5 Mon Sep 17 00:00:00 2001 From: Sharjeel Aziz Date: Wed, 12 Feb 2020 14:06:51 -0500 Subject: [PATCH 018/111] Cleanup and implement style guidelines. (#18980) * Reworded paragraphs to reduce ambiguity. * Added min-kubernetes-server-version metadata. * Converted yaml to a downloadable resource. --- .../declare-network-policy.md | 81 ++++++++----------- .../service/networking/nginx-policy.yaml | 13 +++ 2 files changed, 46 insertions(+), 48 deletions(-) create mode 100644 content/en/examples/service/networking/nginx-policy.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 b282fd6514..edb389c46f 100644 --- a/content/en/docs/tasks/administer-cluster/declare-network-policy.md +++ b/content/en/docs/tasks/administer-cluster/declare-network-policy.md @@ -3,6 +3,7 @@ reviewers: - caseydavenport - danwinship title: Declare Network Policy +min-kubernetes-server-version: v1.8 content_template: templates/task --- {{% capture overview %}} @@ -30,7 +31,7 @@ The above list is sorted alphabetically by product name, not by recommendation o ## Create an `nginx` deployment and expose it via a service -To see how Kubernetes network policy works, start off by creating an `nginx` deployment. +To see how Kubernetes network policy works, start off by creating an `nginx` Deployment. ```console kubectl create deployment nginx --image=nginx @@ -39,7 +40,7 @@ kubectl create deployment nginx --image=nginx deployment.apps/nginx created ``` -And expose it via a service. +Expose the Deployment through a Service called `nginx`. ```console kubectl expose deployment nginx --port=80 @@ -49,7 +50,7 @@ kubectl expose deployment nginx --port=80 service/nginx exposed ``` -This runs a `nginx` pods in the default namespace, and exposes it through a service called `nginx`. +The above commands create a Deployment with an nginx Pod and expose the Deployment through a Service named `nginx`. The `nginx` Pod and Deployment are found in the `default` namespace. ```console kubectl get svc,pod @@ -64,59 +65,43 @@ NAME READY STATUS RESTARTS AGE pod/nginx-701339712-e0qfq 1/1 Running 0 35s ``` -## Test the service by accessing it from another pod +## Test the service by accessing it from another Pod -You should be able to access the new `nginx` service from other pods. To test, access the service from another pod in the default namespace. Make sure you haven't enabled isolation on the namespace. - -Start a busybox container, and use `wget` on the `nginx` service: +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 --generator=run-pod/v1 busybox --rm -ti --image=busybox -- /bin/sh ``` -```console -Waiting for pod default/busybox-472357175-y0m47 to be running, status is Pending, pod ready: false +In your shell, run the following command: -Hit enter for command prompt +```shell +wget --spider --timeout=1 nginx +``` -/ # wget --spider --timeout=1 nginx +```none Connecting to nginx (10.100.0.16:80) -/ # +remote file exists ``` ## Limit access to the `nginx` service -Let's say you want to limit access to the `nginx` service so that only pods with the label `access: true` can query it. To do that, create a `NetworkPolicy` that allows connections only from those pods: +To limit the access to the `nginx` service so that only Pods with the label `access: true` can query it, create a NetworkPolicy object as follows: -```yaml -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: access-nginx -spec: - podSelector: - matchLabels: - app: nginx - ingress: - - from: - - podSelector: - matchLabels: - access: "true" -``` +{{< codenew file="service/networking/nginx-policy.yaml" >}} {{< note >}} -In the case, the label `app=nginx` is automatically added. +NetworkPolicy includes a `podSelector` which selects the grouping of Pods to which the policy applies. You can see this policy selects Pods with the label `app=nginx`. The label was automatically added to the Pod in the `nginx` Deployment. An empty `podSelector` selects all pods in the namespace. {{< /note >}} - ## Assign the policy to the service -Use kubectl to create a NetworkPolicy from the above nginx-policy.yaml file: +Use kubectl to create a NetworkPolicy from the above `nginx-policy.yaml` file: ```console -kubectl apply -f nginx-policy.yaml +kubectl apply -f https://k8s.io/examples/service/networking/nginx-policy.yaml ``` ```none @@ -124,40 +109,40 @@ networkpolicy.networking.k8s.io/access-nginx created ``` ## Test access to the service when access label is not defined -If we attempt to access the nginx Service from a pod without the correct labels, the request will now time out: +When you attempt to access the `nginx` Service from a Pod without the correct labels, the request times out: ```console kubectl run --generator=run-pod/v1 busybox --rm -ti --image=busybox -- /bin/sh ``` -```console -Waiting for pod default/busybox-472357175-y0m47 to be running, status is Pending, pod ready: false +In your shell, run the command: -Hit enter for command prompt +```shell +wget --spider --timeout=1 nginx +``` -/ # wget --spider --timeout=1 nginx +```none Connecting to nginx (10.100.0.16:80) wget: download timed out -/ # ``` ## Define access label and test again -Create a pod with the correct labels, and you'll see that the request is allowed: +You can create a Pod with the correct labels to see that the request is allowed: ```console kubectl run --generator=run-pod/v1 busybox --rm -ti --labels="access=true" --image=busybox -- /bin/sh ``` -```console -Waiting for pod default/busybox-472357175-y0m47 to be running, status is Pending, pod ready: false +In your shell, run the command: -Hit enter for command prompt - -/ # wget --spider --timeout=1 nginx -Connecting to nginx (10.100.0.16:80) -/ # +```shell +wget --spider --timeout=1 nginx ``` + +```none +Connecting to nginx (10.100.0.16:80) +remote file exists +``` + {{% /capture %}} - - diff --git a/content/en/examples/service/networking/nginx-policy.yaml b/content/en/examples/service/networking/nginx-policy.yaml new file mode 100644 index 0000000000..89ee988692 --- /dev/null +++ b/content/en/examples/service/networking/nginx-policy.yaml @@ -0,0 +1,13 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: access-nginx +spec: + podSelector: + matchLabels: + app: nginx + ingress: + - from: + - podSelector: + matchLabels: + access: "true" From 5ae479fc4df84b6f02d3475898d2ca1208dc5fb2 Mon Sep 17 00:00:00 2001 From: Antonio Ojea <6450081+aojea@users.noreply.github.com> Date: Wed, 12 Feb 2020 20:48:50 +0100 Subject: [PATCH 019/111] Add IPv6 DNS records to the dns pod service docs (#19079) --- .../services-networking/dns-pod-service.md | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/content/en/docs/concepts/services-networking/dns-pod-service.md b/content/en/docs/concepts/services-networking/dns-pod-service.md index 63c6b59e7b..8e790151f2 100644 --- a/content/en/docs/concepts/services-networking/dns-pod-service.md +++ b/content/en/docs/concepts/services-networking/dns-pod-service.md @@ -38,14 +38,16 @@ For more up-to-date specification, see ## Services -### A records +### A/AAAA records -"Normal" (not headless) Services are assigned a DNS A record for a name of the -form `my-svc.my-namespace.svc.cluster-domain.example`. This resolves to the cluster IP +"Normal" (not headless) Services are assigned a DNS A or AAAA record, +depending on the IP family of the service, for a name of the form +`my-svc.my-namespace.svc.cluster-domain.example`. This resolves to the cluster IP of the Service. -"Headless" (without a cluster IP) Services are also assigned a DNS A record for -a name of the form `my-svc.my-namespace.svc.cluster-domain.example`. Unlike normal +"Headless" (without a cluster IP) Services are also assigned a DNS A or AAAA record, +depending on the IP family of the service, for a name of the form +`my-svc.my-namespace.svc.cluster-domain.example`. Unlike normal Services, this resolves to the set of IPs of the pods selected by the Service. Clients are expected to consume the set or else use standard round-robin selection from the set. @@ -128,22 +130,22 @@ spec: ``` If there exists a headless service in the same namespace as the pod and with -the same name as the subdomain, the cluster's KubeDNS Server also returns an A +the same name as the subdomain, the cluster's DNS Server also returns an A or AAAA record for the Pod's fully qualified hostname. For example, given a Pod with the hostname set to "`busybox-1`" and the subdomain set to "`default-subdomain`", and a headless Service named "`default-subdomain`" in the same namespace, the pod will see its own FQDN as "`busybox-1.default-subdomain.my-namespace.svc.cluster-domain.example`". DNS serves an -A record at that name, pointing to the Pod's IP. Both pods "`busybox1`" and -"`busybox2`" can have their distinct A records. +A or AAAA record at that name, pointing to the Pod's IP. Both pods "`busybox1`" and +"`busybox2`" can have their distinct A or AAAA records. The Endpoints object can specify the `hostname` for any endpoint addresses, along with its IP. {{< note >}} -Because A records are not created for Pod names, `hostname` is required for the Pod's A +Because A or AAAA records are not created for Pod names, `hostname` is required for the Pod's A or AAAA record to be created. A Pod with no `hostname` but with `subdomain` will only create the -A record for the headless service (`default-subdomain.my-namespace.svc.cluster-domain.example`), +A or AAAA record for the headless service (`default-subdomain.my-namespace.svc.cluster-domain.example`), pointing to the Pod's IP address. Also, Pod needs to become ready in order to have a record unless `publishNotReadyAddresses=True` is set on the Service. {{< /note >}} From d15314ca883a94469beab2185bdd096675888503 Mon Sep 17 00:00:00 2001 From: Patrik Date: Wed, 12 Feb 2020 21:05:52 +0100 Subject: [PATCH 020/111] fix error in StartupProbe feature gate (#19098) Signed-off-by: Patrik Cyvoct --- .../reference/command-line-tools-reference/feature-gates.md | 2 +- 1 file changed, 1 insertion(+), 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 6c0ca8f273..b02b3e48bd 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 @@ -128,7 +128,7 @@ different Kubernetes components. | `ServerSideApply` | `false` | Alpha | 1.14 | 1.15 | | `ServerSideApply` | `true` | Beta | 1.16 | | | `ServiceNodeExclusion` | `false` | Alpha | 1.8 | | -| `StartupProbe` | `true` | Beta | 1.17 | | +| `StartupProbe` | `false` | Alpha | 1.16 | | | `StorageVersionHash` | `false` | Alpha | 1.14 | 1.14 | | `StorageVersionHash` | `true` | Beta | 1.15 | | | `StreamingProxyRedirects` | `false` | Beta | 1.5 | 1.5 | From a35ce86c0a67d1239f79cfe227a98b2638d1c292 Mon Sep 17 00:00:00 2001 From: Yudi A Phanama <11147376+phanama@users.noreply.github.com> Date: Thu, 13 Feb 2020 07:10:35 +0700 Subject: [PATCH 021/111] Add id/resource_quotas localization (#18643) * Add id/resource_quotas localization Signed-off-by: Yudi A Phanama * Fix id/resource_quotas localization Signed-off-by: Yudi A Phanama * Minor fix to resource quota id localization Signed-off-by: Yudi A Phanama --- .../docs/concepts/policy/resource-quotas.md | 622 ++++++++++++++++++ 1 file changed, 622 insertions(+) create mode 100644 content/id/docs/concepts/policy/resource-quotas.md diff --git a/content/id/docs/concepts/policy/resource-quotas.md b/content/id/docs/concepts/policy/resource-quotas.md new file mode 100644 index 0000000000..b4a3e28ebb --- /dev/null +++ b/content/id/docs/concepts/policy/resource-quotas.md @@ -0,0 +1,622 @@ +--- +title: Resource Quota +content_template: templates/concept +weight: 10 +--- + +{{% capture overview %}} + +Saat beberapa pengguna atau tim berbagi sebuah klaster dengan jumlah Node yang tetap, +ada satu hal yang perlu diperhatikan yaitu suatu tim dapat menggunakan sumber daya +lebih dari jatah yang mereka perlukan. + +_Resource Quota_ (kuota sumber daya) adalah sebuah alat yang dapat digunakan oleh +administrator untuk mengatasi hal ini. + +{{% /capture %}} + +{{% capture body %}} + +Sebuah Resource Quota, didefinisikan oleh objek API `ResourceQuota`, menyediakan batasan-batasan +yang membatasi konsumsi gabungan sumber daya komputasi untuk tiap Namespace. Resource Quota dapat +membatasi jumlah objek yang dapat dibuat dalam sebuah Namespace berdasarkan tipenya, maupun jumlah +seluruh sumber daya komputasi yang dapat dipakai oleh sumber daya API (misalnya Pod) di Namespace +tersebut. + +Resource Quota bekerja sebagai berikut: + +- Tim-tim berbeda bekerja pada Namespace yang berbeda pula. Sekarang hal ini belum diwajibkan, + tetapi dukungan untuk mewajibkannya melalui ACL sedang direncanakan. +- Administrator membuat sebuah `ResourceQuota` untuk setiap Namespace. +- Para pengguna membuat sumber daya (Pod, Service, dll.) di dalam Namespace tersebut, kemudian + sistem kuota memantau penggunaan untuk memastikan bahwa penggunaannya tidak melebihi batas + sumber daya yang ditentukan di `ResourceQuota`. +- Jika pembuatan atau pembaruan sebuah sumber daya melanggar sebuah batasan kuota, maka permintaan + tersebut akan gagal dengan kode status `403 FORBIDDEN` dengan sebuah pesan yang menjelaskan batasan + yang akan dilanggar. +- Jika kuota diaktifkan di sebuah Namespace untuk sumber daya komputasi seperti `cpu` dan `memory`, + pengguna-pengguna harus menentukan `requests` atau `limits` untuk sumber daya tersebut; atau sistem + kuota akan menolak pembuatan Pod tersebut. Petunjuk: Gunakan Admission Controller `LimitRanger` untuk + memaksa nilai-nilai bawaan untuk Pod-Pod yang tidak menentukan kebutuhan sumber daya komputasi. + Lihat [petunjuknya](/docs/tasks/administer-cluster/quota-memory-cpu-namespace/) untuk contoh bagaimana + cara menghindari masalah ini. + +Contoh-contoh kebijakan yang dapat dibuat menggunakan Namespace dan kuota adalah: + +- Dalam sebuah klaster dengan kapasitas RAM 32 GiB, dan CPU 16 _core_, misalkan tim A menggunakan 20GiB + dan 10 _core_, dan tim B menggunakan 10GiB dan 4 _core_, dan menyimpan 2GiB dan 2 _core_ untuk cadangan + penggunaan di masa depan. +- Batasi Namespace "testing" dengan batas 1 _core_ dan RAM 1GiB. Biarkan Namespace "production" menggunakan + berapapun jumlah yang diinginkan. + +Pada kasus di mana total kapasitas klaster lebih sedikit dari jumlah seluruh kuota di seluruh Namespace, +dapat terjadi perebutan sumber daya komputasi. Masalah ini akan ditangani dengan cara siapa-cepat-dia-dapat. + +Perebutan sumber daya komputasi maupun perubahan kuota tidak akan memengaruhi sumber daya yang sudah dibuat +sebelumnya. + +## Mengaktifkan Resource Quota + +Dukungan untuk Resource Quota diaktifkan secara bawaan pada banyak distribusi Kubernetes. Resource Quota +diaktifkan saat _flag_ `--enable-admission-plugins=` pada apiserver memiliki `ResourceQuota` sebagai +salah satu nilainya. + +Sebuah Resource Quota akan dipaksakan pada sebuah Namespace tertentu saat ada sebuah objek `ResourceQuota` +di dalam Namespace tersebut. + +## Resource Quota Komputasi + +Kamu dapat membatasi jumlah total [sumber daya komputasi](/docs/user-guide/compute-resources) yang dapat +diminta di dalam sebuah Namespace. + +Berikut jenis-jenis sumber daya yang didukung: + +| Nama Sumber Daya | Deskripsi | +| --------------------- | ----------------------------------------------------------- | +| `limits.cpu` | Pada seluruh Pod yang berada pada kondisi non-terminal, jumlah `limits` CPU tidak dapat melebihi nilai ini. | +| `limits.memory` | Pada seluruh Pod yang berada pada kondisi non-terminal, jumlah `limits` memori tidak dapat melebihi nilai ini. | +| `limits.cpu` | Pada seluruh Pod yang berada pada kondisi non-terminal, jumlah `requests` CPU tidak dapat melebihi nilai ini. | +| `limits.memory` | Pada seluruh Pod yang berada pada kondisi non-terminal, jumlah `requests` memori tidak dapat melebihi nilai ini. | + +### Resource Quota untuk sumber daya yang diperluas + +Sebagai tambahan untuk sumber daya yang disebutkan di atas, pada rilis 1.10, dukungan kuota untuk +[sumber daya yang diperluas](/docs/concepts/configuration/manage-compute-resources-container/#extended-resources) ditambahkan. + +Karena _overcommit_ tidak diperbolehkan untuk sumber daya yang diperluas, tidak masuk akal untuk menentukan +keduanya; `requests` dan `limits` untuk sumber daya yang diperluas yang sama pada sebuah kuota. Jadi, untuk +sumber daya yang diperluas, hanya kuota dengan prefiks `requests.` saja yang diperbolehkan untuk sekarang. + +Mari kita ambil contoh sumber daya GPU. Jika nama sumber dayanya adalah `nvidia.com/gpu`, dan kamu ingin +membatasi jumlah total GPU yang diminta pada sebuah Namespace menjadi 4, kamu dapat menentukan sebuah kuota +sebagai berikut: + +* `requests.nvidia.com/gpu: 4` + +Lihat [Melihat dan Menyetel Kuota](#melihat-dan-menyetel-kuota) untuk informasi lebih lanjut. + + +## Resource Quota untuk penyimpanan + +Kamu dapat membatasi jumlah total [sumber daya penyimpanan](/docs/concepts/storage/persistent-volumes/) yang dapat +diminta pada sebuah Namespace. + +Sebagai tambahan, kamu dapat membatasi penggunaan sumber daya penyimpanan berdasarkan _storage class_ +sumber daya penyimpanan tersebut. + +| Nama Sumber Daya | Deskripsi | +| --------------------- | ----------------------------------------------------------- | +| `requests.storage` | Pada seluruh Persistent Volume Claim, jumlah `requests` penyimpanan tidak dapat melebihi nilai ini. | +| `persistentvolumeclaims` | Jumlah kuantitas [Persistent Volume Claim](/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims) yang dapat ada di dalam sebuah Namespace. | +| `.storageclass.storage.k8s.io/requests.storage` | Pada seluruh Persistent Volume Claim yang dikaitkan dengan sebuah nama _storage-class_ (melalui kolom `storageClassName`), jumlah permintaan penyimpanan tidak dapat melebihi nilai ini. | +| `.storageclass.storage.k8s.io/persistentvolumeclaims` | Pada seluruh Persistent Volume Claim yang dikaitkan dengan sebuah nama _storage-class_ (melalui kolom `storageClassName`), jumlah kuantitas [Persistent Volume Claim](/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims) yang dapat ada di dalam sebuah Namespace. | + +Sebagai contoh, jika sebuah operator ingin membatasi penyimpanan dengan Storage Class `gold` yang berbeda dengan Storage Class `bronze`, maka operator tersebut dapat menentukan kuota sebagai berikut: + +* `gold.storageclass.storage.k8s.io/requests.storage: 500Gi` +* `bronze.storageclass.storage.k8s.io/requests.storage: 100Gi` + +Pada rilis 1.8, dukungan kuota untuk penyimpanan lokal sementara (_local ephemeral storage_) ditambahkan sebagai +sebuah fitur _alpha_: + +| Nama Sumber Daya | Deskripsi | +| ------------------------------- |----------------------------------------------------------- | +| `requests.ephemeral-storage` | Pada seluruh Pod di sebuah Namespace, jumlah `requests` penyimpanan lokal sementara tidak dapat melebihi nilai ini. | +| `limits.ephemeral-storage` | Pada seluruh Pod di sebuah Namespace, jumlah `limits` penyimpanan lokal sementara tidak dapat melebihi nilai ini. | + +## Kuota Kuantitas Objek + +Rilis 1.9 menambahkan dukungan untuk membatasi semua jenis sumber daya standar yang berada pada sebuah Namespace dengan sintaksis sebagai berikut: + +* `count/.` + +Berikut contoh-contoh sumber daya yang dapat ditentukan pengguna pada kuota kuantitas objek: + +* `count/persistentvolumeclaims` +* `count/services` +* `count/secrets` +* `count/configmaps` +* `count/replicationcontrollers` +* `count/deployments.apps` +* `count/replicasets.apps` +* `count/statefulsets.apps` +* `count/jobs.batch` +* `count/cronjobs.batch` +* `count/deployments.extensions` + +Rilis 1.15 menambahkan dukungan untuk sumber daya _custom_ menggunakan sintaksis yang sama. +Contohnya, untuk membuat kuota pada sumber daya _custom_ `widgets` pada grup API `example.com`, gunakan +`count/widgets.example.com`. + +Saat menggunakan Resource Quota `count/*`, sebuah objek akan menggunakan kuotanya jika ia berada pada penyimpanan Apiserver. +Tipe-tipe kuota ini berguna untuk menjaga dari kehabisan sumber daya penyimpanan. Misalnya, kamu mungkin +ingin membatasi kuantitas objek Secret pada sebuah Apiserver karena ukuran mereka yang besar. Terlalu banyak +Secret pada sebuah klaster bahkan dapat membuat Server dan Controller tidak dapat dijalankan! Kamu dapat membatasi +jumlah Job untuk menjaga dari CronJob yang salah dikonfigurasi sehingga membuat terlalu banyak Job pada sebuah +Namespace yang mengakibatkan _denial of service_. + +Sebelum rilis 1.9, kita tidak dapat melakukan pembatasan kuantitas objek generik pada kumpulan sumber daya yang terbatas. +Sebagai tambahan, kita dapat membatasi lebih lanjut sumber daya tertentu dengan kuota berdasarkan jenis mereka. + +Berikut jenis-jenis yang telah didukung: + +| Nama Sumber Daya | Deskripsi | +| ------------------------------- | ------------------------------------------------- | +| `configmaps` | Jumlah total ConfigMap yang dapat berada pada suatu Namespace. | +| `persistentvolumeclaims` | Jumlah total PersistentVolumeClaim[persistent volume claims](/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims) yang dapat berada pada suatu Namespace. | +| `pods` | Jumlah total Pod yang berada pada kondisi non-terminal yang dapat berada pada suatu Namespace. Sebuah Pod berada kondisi terminal yaitu jika `.status.phase in (Failed, Succeded)` adalah `true`. | +| `replicationcontrollers` | Jumlah total ReplicationController yang dapat berada pada suatu Namespace. | +| `resourcequotas` | Jumlah total [ResourceQuota](/docs/reference/access-authn-authz/admission-controllers/#resourcequota) yang dapat berada pada suatu Namespace. | +| `services` | Jumlah total Service yang dapat berada pada suatu Namespace. | +| `services.loadbalancers` | Jumlah total Service dengan tipe LoadBalancer yang dapat berada pada suatu Namespace. | +| `services.nodeports` | Jumlah total Service dengan tipe NodePort yang dapat berada pada suatu Namespace. | +| `secrets` | Jumlah total Secret yang dapat berada pada suatu Namespace. | + +Sebagai contoh, `pods` membatasi kuantitas dan memaksa kuantitas maksimum `pods` yang +berada pada kondisi non-terminal yang dibuat pada sebuah Namespace. Kamu mungkin ingin +menyetel kuota `pods` pada sebuah Namespace untuk menghindari kasus di mana pengguna membuat +banyak Pod kecil dan menghabiskan persediaan alamat IP Pod pada klaster. + +## Lingkup Kuota + +Setiap kuota dapat memiliki kumpulan lingkup yang dikaitkan. Sebuah kuota hanya akan mengukur penggunaan sebuah +sumber daya jika sumber daya tersebut cocok dengan irisan dari lingkup-lingkup yang ditentukan. + +Saat sebuah lingkup ditambahkan kepada kuota, lingkup itu akan membatasi kuantitas sumber daya yang didukung menjadi yang berkaitan dengan lingkup tersebut. +Sumber daya yang ditentukan pada kuota di luar kumpulan yang diizinkan akan menghasilkan kesalahan validasi. + +| Lingkup | Deskripsi | +| ----- | ----------- | +| `Terminating` | Mencocokkan dengan Pod-Pod yang memiliki `.spec.activeDeadlineSeconds >= 0` | +| `NotTerminating` | Mencocokkan dengan Pod-Pod yang memiliki `.spec.activeDeadlineSeconds is nil` | +| `BestEffort` | Mencocokkan dengan Pod-Pod yang memiliki _quality of service_ bertipe _best effort_. | +| `NotBestEffort` | Mencocokkan dengan Pod-Pod yang tidak memiliki _quality of service_ bertipe _best effort_. | + +Lingkup `BestEffort` membatasi sebuah kuota untuk memantau sumber daya berikut: `pods` + +Lingkup `Terminating`, `NotTerminating`, dan `NotBestEffort` membatasi sebuah kuota untuk memantau sumber daya berikut: + +* `cpu` +* `limits.cpu` +* `limits.memory` +* `memory` +* `pods` +* `requests.cpu` +* `requests.memory` + +### Resource Quota Per PriorityClass + +{{< feature-state for_k8s_version="1.12" state="beta" >}} + +Pod-Pod dapat dibuat dengan sebuah [Priority (prioritas)](/docs/concepts/configuration/pod-priority-preemption/#pod-priority) tertentu. +Kamu dapat mengontrol konsumsi sumber daya sistem sebuah Pod berdasarkan Priority Pod tersebut, menggunakan +kolom `scopeSelector` pada spesifikasi kuota tersebut. + +Sebuah kuota dicocokkan dan digunakan hanya jika `scopeSelector` pada spesifikasi kuota tersebut memilih Pod tersebut. + +Contoh ini membuat sebuah objek kuota dan mencocokkannya dengan Pod-Pod pada Priority tertentu. Contoh tersebut +bekerja sebagai berikut: + +- Pod-Pod di dalam klaster memiliki satu dari tiga Priority Class, "low", "medium", "high". +- Satu objek kuota dibuat untuk setiap Priority. + +Simpan YAML berikut ke sebuah berkas bernama `quota.yml`. + +```yaml +apiVersion: v1 +kind: List +items: +- apiVersion: v1 + kind: ResourceQuota + metadata: + name: pods-high + spec: + hard: + cpu: "1000" + memory: 200Gi + pods: "10" + scopeSelector: + matchExpressions: + - operator : In + scopeName: PriorityClass + values: ["high"] +- apiVersion: v1 + kind: ResourceQuota + metadata: + name: pods-medium + spec: + hard: + cpu: "10" + memory: 20Gi + pods: "10" + scopeSelector: + matchExpressions: + - operator : In + scopeName: PriorityClass + values: ["medium"] +- apiVersion: v1 + kind: ResourceQuota + metadata: + name: pods-low + spec: + hard: + cpu: "5" + memory: 10Gi + pods: "10" + scopeSelector: + matchExpressions: + - operator : In + scopeName: PriorityClass + values: ["low"] +``` + +Terapkan YAML tersebut dengan `kubectl create`. + +```shell +kubectl create -f ./quota.yml +``` + +```shell +resourcequota/pods-high created +resourcequota/pods-medium created +resourcequota/pods-low created +``` + +Pastikan bahwa kuota `Used` adalah `0` dengan `kubectl describe quota`. + +```shell +kubectl describe quota +``` + +```shell +Name: pods-high +Namespace: default +Resource Used Hard +-------- ---- ---- +cpu 0 1k +memory 0 200Gi +pods 0 10 + + +Name: pods-low +Namespace: default +Resource Used Hard +-------- ---- ---- +cpu 0 5 +memory 0 10Gi +pods 0 10 + + +Name: pods-medium +Namespace: default +Resource Used Hard +-------- ---- ---- +cpu 0 10 +memory 0 20Gi +pods 0 10 +``` + +Buat sebuah Pod dengan Priority "high". Simpan YAML berikut ke sebuah +berkas bernama `high-priority-pod.yml`. + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: high-priority +spec: + containers: + - name: high-priority + image: ubuntu + command: ["/bin/sh"] + args: ["-c", "while true; do echo hello; sleep 10;done"] + resources: + requests: + memory: "10Gi" + cpu: "500m" + limits: + memory: "10Gi" + cpu: "500m" + priorityClassName: high +``` + +Terapkan dengan `kubectl create`. + +```shell +kubectl create -f ./high-priority-pod.yml +``` + +Pastikan bahwa status "Used" untuk kuota dengan Priority "high", `pods-high`, telah berubah +dan dua kuota lainnya tidak berubah. + +```shell +kubectl describe quota +``` + +```shell +Name: pods-high +Namespace: default +Resource Used Hard +-------- ---- ---- +cpu 500m 1k +memory 10Gi 200Gi +pods 1 10 + + +Name: pods-low +Namespace: default +Resource Used Hard +-------- ---- ---- +cpu 0 5 +memory 0 10Gi +pods 0 10 + + +Name: pods-medium +Namespace: default +Resource Used Hard +-------- ---- ---- +cpu 0 10 +memory 0 20Gi +pods 0 10 +``` + +`scopeSelector` mendukung nilai-nilai berikut pada kolom `operator`: + +* `In` +* `NotIn` +* `Exist` +* `DoesNotExist` + +## _Request_ vs Limit + +Saat mengalokasikan sumber daya komputasi, setiap Container dapat menentukan sebuah nilai _request_ (permintaan) dan limit untuk CPU atau memori. +Kuota tersebut dapat dikonfigurasi untuk membatasi nilai salah satunya. + +Jika kuota tersebut memiliki sebuah nilai yang ditentukan untuk `requests.cpu` atau `requests.memory`, maka kuota +tersebut mengharuskan setiap Container yang akan dibuat untuk menentukan request eksplisit untuk sumber daya tersebut. +Jika kuota tersebut memiliki sebuah nilai yang ditentukan untuk `limits.cpu` atau `limits.memory`, maka kuota tersebut +mengharuskan setiap Container yang akan dibuat untuk menentukan limit eksplisit untuk sumber daya tersebut. + +## Melihat dan Menyetel kuota + +Kubectl mendukung membuat, membarui, dan melihat kuota: + +```shell +kubectl create namespace myspace +``` + +```shell +cat < compute-resources.yaml +apiVersion: v1 +kind: ResourceQuota +metadata: + name: compute-resources +spec: + hard: + requests.cpu: "1" + requests.memory: 1Gi + limits.cpu: "2" + limits.memory: 2Gi + requests.nvidia.com/gpu: 4 +EOF +``` + +```shell +kubectl create -f ./compute-resources.yaml --namespace=myspace +``` + +```shell +cat < object-counts.yaml +apiVersion: v1 +kind: ResourceQuota +metadata: + name: object-counts +spec: + hard: + configmaps: "10" + persistentvolumeclaims: "4" + pods: "4" + replicationcontrollers: "20" + secrets: "10" + services: "10" + services.loadbalancers: "2" +EOF +``` + +```shell +kubectl create -f ./object-counts.yaml --namespace=myspace +``` + +```shell +kubectl get quota --namespace=myspace +``` + +```shell +NAME AGE +compute-resources 30s +object-counts 32s +``` + +```shell +kubectl describe quota compute-resources --namespace=myspace +``` + +```shell +Name: compute-resources +Namespace: myspace +Resource Used Hard +-------- ---- ---- +limits.cpu 0 2 +limits.memory 0 2Gi +requests.cpu 0 1 +requests.memory 0 1Gi +requests.nvidia.com/gpu 0 4 +``` + +```shell +kubectl describe quota object-counts --namespace=myspace +``` + +```shell +Name: object-counts +Namespace: myspace +Resource Used Hard +-------- ---- ---- +configmaps 0 10 +persistentvolumeclaims 0 4 +pods 0 4 +replicationcontrollers 0 20 +secrets 1 10 +services 0 10 +services.loadbalancers 0 2 +``` + +Kubectl juga mendukung kuota kuantitas objek untuk semua sumber daya standar yang berada pada Namespace +menggunakan sintaksis `count/.`: + +```shell +kubectl create namespace myspace +``` + +```shell +kubectl create quota test --hard=count/deployments.extensions=2,count/replicasets.extensions=4,count/pods=3,count/secrets=4 --namespace=myspace +``` + +```shell +kubectl run nginx --image=nginx --replicas=2 --namespace=myspace +``` + +```shell +kubectl describe quota --namespace=myspace +``` + +```shell +Name: test +Namespace: myspace +Resource Used Hard +-------- ---- ---- +count/deployments.extensions 1 2 +count/pods 2 3 +count/replicasets.extensions 1 4 +count/secrets 1 4 +``` + +## Kuota dan Kapasitas Klaster + +`ResourceQuota` tidak tergantung pada kapasitas klaster. `ResourceQuota` ditentukan dalam +satuan-satuan absolut. Jadi, jika kamu menambahkan Node ke klaster kamu, penambahan ini +**bukan** berarti secara otomatis memberikan setiap Namespace kemampuan untuk menggunakan +lebih banyak sumber daya. + +Terkadang kebijakan yang lebih kompleks mungkin lebih diinginkan, seperti: + + - Secara proporsional membagi sumber daya total klaster untuk beberapa tim. + - Mengizinkan setiap tim untuk meningkatkan penggunaan sumber daya sesuai kebutuhan, + tetapi tetap memiliki batas yang cukup besar untuk menghindari kehabisan sumber daya. + - Mendeteksi permintaan dari sebuah Namespace, menambah Node, kemudian menambah kuota. + +Kebijakan-kebijakan seperti itu dapat diterapkan dengan `ResourceQuota` sebagai dasarnya, +dengan membuat sebuah "pengontrol" yang memantau penggunaan kuota dan menyesuaikan batas +keras kuota untuk setiap Namespace berdasarkan sinyal-sinyal lainnya. + +Perlu dicatat bahwa Resource Quota membagi agregat sumber daya klaster, tapi Resource Quota +tidak membuat batasan-batasan terhadap Node: Pod-Pod dari beberapa Namespace boleh berjalan +di Node yang sama. + +## Membatasi konsumsi Priority Class secara bawaan + +Mungkin saja diinginkan untuk Pod-Pod pada kelas prioritas tertentu, misalnya "cluster-services", sebaiknya diizinkan pada sebuah Namespace, jika dan hanya jika terdapat sebuah objek kuota yang cocok. + +Dengan mekanisme ini, operator-operator dapat membatasi penggunaan Priority Class dengan prioritas tinggi pada Namespace-Namespace tertentu saja dan tidak semua Namespace dapat menggunakan Priority Class tersebut secara bawaan. + +Untuk memaksa aturan ini, _flag_ kube-apiserver `--admission-control-config-file` sebaiknya digunakan untuk memberikan _path_ menuju berkas konfigurasi berikut: + +{{< tabs name="example1" >}} +{{% tab name="apiserver.config.k8s.io/v1" %}} + +```yaml +apiVersion: apiserver.config.k8s.io/v1 +kind: AdmissionConfiguration +plugins: +- name: "ResourceQuota" + configuration: + apiVersion: apiserver.config.k8s.io/v1 + kind: ResourceQuotaConfiguration + limitedResources: + - resource: pods + matchScopes: + - scopeName: PriorityClass + operator: In + values: ["cluster-services"] +``` + +{{% /tab %}} +{{% tab name="apiserver.k8s.io/v1alpha1" %}} + +```yaml +# Kedaluwarsa pada v1.17 digantikan oleh apiserver.config.k8s.io/v1 +apiVersion: apiserver.k8s.io/v1alpha1 +kind: AdmissionConfiguration +plugins: +- name: "ResourceQuota" + configuration: + # Kedaluwarsa pada v1.17 digantikan oleh apiserver.config.k8s.io/v1, ResourceQuotaConfiguration + apiVersion: resourcequota.admission.k8s.io/v1beta1 + kind: Configuration + limitedResources: + - resource: pods + matchScopes: + - scopeName: PriorityClass + operator: In + values: ["cluster-services"] +``` + +{{% /tab %}} +{{< /tabs >}} + +Sekarang, Pod-Pod "cluster-services" akan diizinkan hanya pada Namespace di mana ada sebuah objek kuota dengan sebuah `scopeSelector` yang cocok. + +Contohnya: + +```yaml + scopeSelector: + matchExpressions: + - scopeName: PriorityClass + operator: In + values: ["cluster-services"] +``` + +Lihat [LimitedResources](https://github.com/kubernetes/kubernetes/pull/36765) dan [dokumen desain dukungan Quota untuk Priority Class](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/scheduling/pod-priority-resourcequota.md) untuk informasi lebih lanjut. + +## Contoh + +Lihat [contoh detail cara menggunakan sebuah Resource Quota](/docs/tasks/administer-cluster/quota-api-object/). + +{{% /capture %}} + +{{% capture whatsnext %}} + +Lihat [dokumen desain ResourceQuota](https://git.k8s.io/community/contributors/design-proposals/resource-management/admission_control_resource_quota.md) untuk informasi lebih lanjut. + +{{% /capture %}} From ec9e20f556b76c5dc611eb6790e43989538f859f Mon Sep 17 00:00:00 2001 From: Wang Bing Date: Thu, 13 Feb 2020 12:50:35 +0800 Subject: [PATCH 022/111] fix comment display (#19100) --- .../concepts/services-networking/ingress.md | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/content/zh/docs/concepts/services-networking/ingress.md b/content/zh/docs/concepts/services-networking/ingress.md index 5f6b98b6d6..516d0492ad 100644 --- a/content/zh/docs/concepts/services-networking/ingress.md +++ b/content/zh/docs/concepts/services-networking/ingress.md @@ -35,35 +35,45 @@ For clarity, this guide defines the following terms: Node : A worker machine in Kubernetes, part of a cluster. --> -节点(Node) -: Kubernetes 集群中其中一台工作机器,是集群的一部分。 + +节点(Node): + +Kubernetes 集群中其中一台工作机器,是集群的一部分。 -集群(Cluster) -: 一组运行程序(这些程序是容器化的,被 Kubernetes 管理的)的节点。 在此示例中,和在大多数常见的Kubernetes部署方案,集群中的节点都不会是公共网络。 + +集群(Cluster): + +一组运行程序(这些程序是容器化的,被 Kubernetes 管理的)的节点。 在此示例中,和在大多数常见的Kubernetes部署方案,集群中的节点都不会是公共网络。 -边缘路由器(Edge router) -: 在集群中强制性执行防火墙策略的路由器(router)。可以是由云提供商管理的网关,也可以是物理硬件。 + +边缘路由器(Edge router): + +在集群中强制性执行防火墙策略的路由器(router)。可以是由云提供商管理的网关,也可以是物理硬件。 -集群网络(Cluster network) -: 一组逻辑或物理的链接,根据 Kubernetes [网络模型](/docs/concepts/cluster-administration/networking/) 在集群内实现通信。 + +集群网络(Cluster network): + +一组逻辑或物理的链接,根据 Kubernetes [网络模型](/docs/concepts/cluster-administration/networking/) 在集群内实现通信。 + 服务(Service): + Kubernetes {{< glossary_tooltip term_id="service" >}} 使用 {{< glossary_tooltip text="标签" term_id="label" >}} 选择器(selectors)标识的一组 Pod。除非另有说明,否则假定服务只具有在集群网络中可路由的虚拟 IP。 From d856dfcd39f784cf59b2d069dc0fe029e67c5bd1 Mon Sep 17 00:00:00 2001 From: pierwill <19642016+pierwill@users.noreply.github.com> Date: Thu, 13 Feb 2020 00:20:35 -0800 Subject: [PATCH 023/111] Add note on `none` driver in minikube installation docs (#18430) * Add newlines to `none` VM driver docs * Add note on `none` driver in minikube installation docs Link to documentation describing possible security and data loss issues * minikube: Add caution block to `none` vm driver * Edit Debian-related minikube instructions Update section on the `none` driver. --- content/en/docs/tasks/tools/install-minikube.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/content/en/docs/tasks/tools/install-minikube.md b/content/en/docs/tasks/tools/install-minikube.md index 6effe11116..03c3b07cd5 100644 --- a/content/en/docs/tasks/tools/install-minikube.md +++ b/content/en/docs/tasks/tools/install-minikube.md @@ -74,9 +74,17 @@ If you do not already have a hypervisor installed, install one of these now: • [VirtualBox](https://www.virtualbox.org/wiki/Downloads) -{{< note >}} -Minikube also supports a `--vm-driver=none` option that runs the Kubernetes components on the host and not in a VM. Using this driver requires [Docker](https://www.docker.com/products/docker-desktop) and a Linux environment but not a hypervisor. It is recommended to use the apt installation of docker from [Docker](https://www.docker.com/products/docker-desktop), when using the none driver. The snap installation of docker does not work with minikube. -{{< /note >}} +Minikube also supports a `--vm-driver=none` option that runs the Kubernetes components on the host and not in a VM. +Using this driver requires [Docker](https://www.docker.com/products/docker-desktop) and a Linux environment but not a hypervisor. + +If you're using the `none` driver in Debian or a derivative, use the `.deb` packages for +Docker rather than the snap package, which does not work with Minikube. +You can download `.deb` packages from [Docker](https://www.docker.com/products/docker-desktop). + +{{< caution >}} +The `none` VM driver can result in security and data loss issues. +Before using `--vm-driver=none`, consult [this documentation](https://minikube.sigs.k8s.io/docs/reference/drivers/none/) for more information. +{{< /caution >}} ### Install Minikube using a package From b0aac61731aa7199793298b2bbf8fe55e8d7a36e Mon Sep 17 00:00:00 2001 From: Fangyuan Li Date: Thu, 13 Feb 2020 00:52:35 -0800 Subject: [PATCH 024/111] Reduce ambiguity on nodePort (#18928) * Reduce ambiguity on nodePort At first sight, nodePort looks a lot like service.Spec.NodePort, though it just means a port allocated from "--service-node-port-range". Replacing "nodePort" with "node port" to add some clarity. * Update content/en/docs/tasks/access-application-cluster/create-external-load-balancer.md Co-Authored-By: Tim Bannister Co-authored-by: Tim Bannister --- .../create-external-load-balancer.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/content/en/docs/tasks/access-application-cluster/create-external-load-balancer.md b/content/en/docs/tasks/access-application-cluster/create-external-load-balancer.md index 3cf8c0a40b..720203d60d 100644 --- a/content/en/docs/tasks/access-application-cluster/create-external-load-balancer.md +++ b/content/en/docs/tasks/access-application-cluster/create-external-load-balancer.md @@ -127,10 +127,12 @@ IP and may cause a second hop to another node, but should have good overall load-spreading. Local preserves the client source IP and avoids a second hop for LoadBalancer and NodePort type services, but risks potentially imbalanced traffic spreading. -* `service.spec.healthCheckNodePort` - specifies the health check nodePort -(numeric port number) for the service. If not specified, `healthCheckNodePort` is -created by the service API backend with the allocated `nodePort`. It will use the -user-specified `nodePort` value if specified by the client. It only has an +* `service.spec.healthCheckNodePort` - specifies the health check node port +(numeric port number) for the service. If `healthCheckNodePort` isn't specified, +the service controller allocates a port from your cluster's NodePort range. You +can configure that range by setting an API server command line option, +`--service-node-port-range`. It will use the +user-specified `healthCheckNodePort` value if specified by the client. It only has an effect when `type` is set to LoadBalancer and `externalTrafficPolicy` is set to Local. From 669bf498a908a8b488c4c9989a0a35f6f9efe9be Mon Sep 17 00:00:00 2001 From: Nils Martel Date: Thu, 13 Feb 2020 13:36:35 +0100 Subject: [PATCH 025/111] Fix Typo (#19107) --- content/de/docs/reference/kubectl/cheatsheet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/de/docs/reference/kubectl/cheatsheet.md b/content/de/docs/reference/kubectl/cheatsheet.md index 7ab55e20ea..507fbbd50d 100644 --- a/content/de/docs/reference/kubectl/cheatsheet.md +++ b/content/de/docs/reference/kubectl/cheatsheet.md @@ -27,7 +27,7 @@ source <(kubectl completion bash) # Wenn Sie autocomplete in bash in der aktuell echo "source <(kubectl completion bash)" >> ~/.bashrc # Fügen Sie der Bash-Shell dauerhaft Autocomplete hinzu. ``` -Sie können auch ein Abkürzungsalias für `kubectl` verwenden, weleches auch mit Vervollständigung funktioniert: +Sie können auch ein Abkürzungsalias für `kubectl` verwenden, welches auch mit Vervollständigung funktioniert: ```bash alias k=kubectl From aec8c4bcf5cdd9ce315fbb860705d9d6631d5bc5 Mon Sep 17 00:00:00 2001 From: Yushiro FURUKAWA Date: Fri, 14 Feb 2020 04:58:36 +0900 Subject: [PATCH 026/111] Remove trailing spaces from it documents (#16790) --- content/it/community/code-of-conduct.md | 10 +- .../it/docs/concepts/architecture/nodes.md | 6 +- .../cluster-administration/cloud-providers.md | 60 ++++---- .../cluster-administration-overview.md | 4 +- .../controller-metrics.md | 10 +- .../kubelet-garbage-collection.md | 26 ++-- .../manage-deployment.md | 90 +++++------ .../cluster-administration/networking.md | 144 +++++++++--------- .../federation-deprecation-warning-note.md | 4 +- 9 files changed, 177 insertions(+), 177 deletions(-) diff --git a/content/it/community/code-of-conduct.md b/content/it/community/code-of-conduct.md index 2d0b6959ca..7c64183ece 100644 --- a/content/it/community/code-of-conduct.md +++ b/content/it/community/code-of-conduct.md @@ -8,16 +8,16 @@ css: /css/community.css

Codice di condotta della comunità di Kubernetes

-Kubernetes segue il +Kubernetes segue il codice di condotta CNCF. -Il testo del CNC CoC è replicato di seguito a partire dal +Il testo del CNC CoC è replicato di seguito a partire dal commit 0ce4694. Se noti che questo non è aggiornato, ti preghiamo di far presente questo problema. file an issue. -Se noti una violazione del Codice di condotta in occasione di un evento o una riunione, in Slack o in un altro meccanismo di comunicazione, -contatta il Comitato per -il codice di condotta di Kubernetes/a>. +Se noti una violazione del Codice di condotta in occasione di un evento o una riunione, in Slack o in un altro meccanismo di comunicazione, +contatta il Comitato per +il codice di condotta di Kubernetes/a>. Potete raggiungerci via email all'indirizzo conduct@kubernetes.io. Il tuo anonimato sarà protetto. diff --git a/content/it/docs/concepts/architecture/nodes.md b/content/it/docs/concepts/architecture/nodes.md index c7ca78917b..4ad016b327 100644 --- a/content/it/docs/concepts/architecture/nodes.md +++ b/content/it/docs/concepts/architecture/nodes.md @@ -97,7 +97,7 @@ numero di pod che possono essere programmati sul nodo. Informazioni generali sul nodo, come la versione del kernel, la versione di Kubernetes (versione kubelet e kube-proxy), versione Docker (se utilizzata), nome del sistema operativo. -Le informazioni sono raccolte da Kubelet dal nodo. +Le informazioni sono raccolte da Kubelet dal nodo. ## Management @@ -211,7 +211,7 @@ NodeController è responsabile per l'aggiunta di taints corrispondenti ai proble nodo irraggiungibile o non pronto. Vedi [questa documentazione](/docs/concepts/configuration/taint-and-toleration/) per i dettagli su `NoExecute` taints e la funzione alpha. -partire dalla versione 1.8, il controller del nodo può essere reso responsabile della creazione di taints che rappresentano le condizioni del nodo. +partire dalla versione 1.8, il controller del nodo può essere reso responsabile della creazione di taints che rappresentano le condizioni del nodo. Questa è una caratteristica alfa della versione 1.8. ### Self-Registration of Nodes @@ -229,7 +229,7 @@ Per l'autoregistrazione, il kubelet viene avviato con le seguenti opzioni: - `--node-labels` - Etichette da aggiungere quando si registra il nodo nel cluster (vedere le restrizioni dell'etichetta applicate dal [plugin di accesso NodeRestriction](/docs/reference/access-authn-authz/admission-controller/#noderestriction) in 1.13+). - `--node-status-update-frequency` - Specifica la frequenza con cui kubelet invia lo stato del nodo al master -Quando [Node authorization mode](/docs/reference/access-authn-authz/node/) e +Quando [Node authorization mode](/docs/reference/access-authn-authz/node/) e [NodeRestriction admission plugin](/docs/reference/access-authn-authz/admission-controllers/#noderestriction) sono abilitati, kubelets è autorizzato solo a creare / modificare la propria risorsa nodo. diff --git a/content/it/docs/concepts/cluster-administration/cloud-providers.md b/content/it/docs/concepts/cluster-administration/cloud-providers.md index ea2c49533a..5ea917a9c5 100644 --- a/content/it/docs/concepts/cluster-administration/cloud-providers.md +++ b/content/it/docs/concepts/cluster-administration/cloud-providers.md @@ -14,7 +14,7 @@ fornitore di servizi cloud. ### kubeadm [kubeadm](/docs/reference/setup-tools/kubeadm/kubeadm/) è un'opzione popolare per la creazione di cluster di kuberneti. -kubeadm ha opzioni di configurazione per specificare le informazioni di configurazione per i provider cloud. Ad esempio +kubeadm ha opzioni di configurazione per specificare le informazioni di configurazione per i provider cloud. Ad esempio un tipico il provider cloud in-tree può essere configurato utilizzando kubeadm come mostrato di seguito: ```yaml @@ -46,15 +46,15 @@ controllerManager: mountPath: "/etc/kubernetes/cloud.conf" ``` -I provider cloud in-tree in genere richiedono sia `--cloud-provider` e` --cloud-config` specificati nelle righe di +I provider cloud in-tree in genere richiedono sia `--cloud-provider` e` --cloud-config` specificati nelle righe di comando per [kube-apiserver](/docs/admin/kube-apiserver/), [kube-controller-manager](/docs/admin/kube-controller-manager/) -e il [Kubelet](/docs/admin/kubelet/). Anche il contenuto del file specificato in `--cloud-config` per ciascun provider +e il [Kubelet](/docs/admin/kubelet/). Anche il contenuto del file specificato in `--cloud-config` per ciascun provider è documentato di seguito. Per tutti i fornitori di servizi cloud esterni, seguire le istruzioni sui singoli repository. ## AWS -Questa sezione descrive tutte le possibili configurazioni che possono essere utilizzato durante l'esecuzione di +Questa sezione descrive tutte le possibili configurazioni che possono essere utilizzato durante l'esecuzione di Kubernetes su Amazon Web Services. ### Node Name @@ -107,23 +107,23 @@ Le informazioni per le annotazioni per AWS sono tratte dai commenti su [aws.go]( ## Azure ### Node Name -Il provider cloud di Azure utilizza il nome host del nodo (come determinato dal kubelet o sovrascritto -con `--hostname-override`) come nome dell'oggetto Nodo Kubernetes. Si noti che il nome del nodo Kubernetes deve +Il provider cloud di Azure utilizza il nome host del nodo (come determinato dal kubelet o sovrascritto +con `--hostname-override`) come nome dell'oggetto Nodo Kubernetes. Si noti che il nome del nodo Kubernetes deve corrispondere al nome VM di Azure. ## CloudStack ### Node Name -Il provider cloud CloudStack utilizza il nome host del nodo (come determinato dal kubelet o sovrascritto -con `--hostname-override`) come nome dell'oggetto Nodo Kubernetes. Si noti che il nome del nodo Kubernetes deve +Il provider cloud CloudStack utilizza il nome host del nodo (come determinato dal kubelet o sovrascritto +con `--hostname-override`) come nome dell'oggetto Nodo Kubernetes. Si noti che il nome del nodo Kubernetes deve corrispondere al nome VM di CloudStack. ## GCE ### Node Name -Il provider cloud GCE utilizza il nome host del nodo (come determinato dal kubelet o sovrascritto +Il provider cloud GCE utilizza il nome host del nodo (come determinato dal kubelet o sovrascritto con `--hostname-override`) come nome dell'oggetto Nodo Kubernetes. Si noti che il primo segmento del nome del nodo -Kubernetes deve corrispondere al nome dell'istanza GCE (ad esempio, un nodo denominato `kubernetes-node-2.c.my-proj.internal` +Kubernetes deve corrispondere al nome dell'istanza GCE (ad esempio, un nodo denominato `kubernetes-node-2.c.my-proj.internal` deve corrispondere a un'istanza denominata` kubernetes-node-2`) . ## OpenStack @@ -135,7 +135,7 @@ Il provider cloud OpenStack utilizza il nome dell'istanza (come determinato dai Si noti che il nome dell'istanza deve essere un nome nodo Kubernetes valido affinché kubelet registri correttamente il suo oggetto Node. ### Services -Il provider cloud OpenStack implementazione per Kubernetes supporta l'uso di questi servizi OpenStack da la nuvola +Il provider cloud OpenStack implementazione per Kubernetes supporta l'uso di questi servizi OpenStack da la nuvola sottostante, ove disponibile: | Servizio | Versioni API | Richiesto | @@ -252,7 +252,7 @@ file:   L'impostazione predefinita è `false`. Quando è specificato `true` quindi` monitor-delay`,   `monitor-timeout`, e` monitor-max-retries` deve essere impostato. * `monitor-delay` (Opzionale): il tempo tra l'invio delle sonde a -  membri del servizio di bilanciamento del carico. Assicurati di specificare un'unità di tempo valida. Le unità di tempo +  membri del servizio di bilanciamento del carico. Assicurati di specificare un'unità di tempo valida. Le unità di tempo valide sono "ns", "us" (o "μs"), "ms", "s", "m", "h" * `monitor-timeout` (Opzionale): tempo massimo di attesa per un monitor   per una risposta ping prima che scada. Il valore deve essere inferiore al ritardo @@ -346,22 +346,22 @@ File `cloud.conf`: ## OVirt ### Node Name -Il provider di cloud OVirt utilizza il nome host del nodo (come determinato dal kubelet o sovrascritto -con `--hostname-override`) come nome dell'oggetto Nodo Kubernetes. Si noti che il nome del nodo Kubernetes deve +Il provider di cloud OVirt utilizza il nome host del nodo (come determinato dal kubelet o sovrascritto +con `--hostname-override`) come nome dell'oggetto Nodo Kubernetes. Si noti che il nome del nodo Kubernetes deve corrispondere al FQDN del VM (riportato da OVirt in ` ... `) ## Photon ### Node Name -Il provider cloud Photon utilizza il nome host del nodo (come determinato dal kubelet o sovrascritto -con `--hostname-override`) come nome dell'oggetto Nodo Kubernetes. Si noti che il nome del nodo Kubernetes deve -corrispondere al nome VM Photon (o se "overrideIP` è impostato su true in` --cloud-config`, il nome del nodo Kubernetes +Il provider cloud Photon utilizza il nome host del nodo (come determinato dal kubelet o sovrascritto +con `--hostname-override`) come nome dell'oggetto Nodo Kubernetes. Si noti che il nome del nodo Kubernetes deve +corrispondere al nome VM Photon (o se "overrideIP` è impostato su true in` --cloud-config`, il nome del nodo Kubernetes deve corrispondere all'indirizzo IP della macchina virtuale Photon). ## VSphere ### Node Name -Il provider cloud VSphere utilizza il nome host rilevato del nodo (come determinato dal kubelet) come nome dell'oggetto +Il provider cloud VSphere utilizza il nome host rilevato del nodo (come determinato dal kubelet) come nome dell'oggetto Nodo Kubernetes. Il parametro `--hostname-override` viene ignorato dal fornitore di cloud VSphere. @@ -369,31 +369,31 @@ Il parametro `--hostname-override` viene ignorato dal fornitore di cloud VSphere ## IBM Cloud Kubernetes Service ### Compute nodes -Utilizzando il provider di servizi IBM Cloud Kubernetes, è possibile creare cluster con una combinazione di nodi -virtuali e fisici (bare metal) in una singola zona o su più zone in una regione. Per ulteriori informazioni, +Utilizzando il provider di servizi IBM Cloud Kubernetes, è possibile creare cluster con una combinazione di nodi +virtuali e fisici (bare metal) in una singola zona o su più zone in una regione. Per ulteriori informazioni, consultare [Pianificazione dell'installazione di cluster e nodo di lavoro](https://cloud.ibm.com/docs/containers?topic=containers-plan_clusters#plan_clusters). Il nome dell'oggetto Nodo Kubernetes è l'indirizzo IP privato dell'istanza del nodo di lavoro IBM Cloud Kubernetes Service. ### Networking -Il fornitore di servizi IBM Cloud Kubernetes fornisce VLAN per le prestazioni di rete di qualità e l'isolamento della -rete per i nodi. È possibile configurare firewall personalizzati e criteri di rete Calico per aggiungere un ulteriore -livello di sicurezza per il cluster o per connettere il cluster al data center on-prem tramite VPN. Per ulteriori +Il fornitore di servizi IBM Cloud Kubernetes fornisce VLAN per le prestazioni di rete di qualità e l'isolamento della +rete per i nodi. È possibile configurare firewall personalizzati e criteri di rete Calico per aggiungere un ulteriore +livello di sicurezza per il cluster o per connettere il cluster al data center on-prem tramite VPN. Per ulteriori informazioni, vedere [Pianificazione in-cluster e rete privata](https://cloud.ibm.com/docs/containers?topic=containers-cs_network_cluster#cs_network_cluster). -Per esporre le app al pubblico o all'interno del cluster, è possibile sfruttare i servizi NodePort, LoadBalancer o -Ingress. È anche possibile personalizzare il bilanciamento del carico dell'applicazione Ingress con le annotazioni. +Per esporre le app al pubblico o all'interno del cluster, è possibile sfruttare i servizi NodePort, LoadBalancer o +Ingress. È anche possibile personalizzare il bilanciamento del carico dell'applicazione Ingress con le annotazioni. Per ulteriori informazioni, vedere [Pianificazione per esporre le app con reti esterne](https://cloud.ibm.com/docs/containers?topic=containers-cs_network_planning#cs_network_planning). ### Storage -Il fornitore di servizi IBM Cloud Kubernetes sfrutta i volumi persistenti nativi di Kubernetes per consentire agli -utenti di montare archiviazione di file, blocchi e oggetti cloud nelle loro app. È inoltre possibile utilizzare il -componente aggiuntivo database-as-a-service e di terze parti per la memorizzazione permanente dei dati. Per ulteriori +Il fornitore di servizi IBM Cloud Kubernetes sfrutta i volumi persistenti nativi di Kubernetes per consentire agli +utenti di montare archiviazione di file, blocchi e oggetti cloud nelle loro app. È inoltre possibile utilizzare il +componente aggiuntivo database-as-a-service e di terze parti per la memorizzazione permanente dei dati. Per ulteriori informazioni, vedere [Pianificazione dell'archiviazione persistente altamente disponibile](https://cloud.ibm.com/docs/containers?topic=containers-storage_planning#storage_planning). ## Baidu Cloud Container Engine ### Node Name -Il provider di cloud Baidu utilizza l'indirizzo IP privato del nodo (come determinato dal kubelet o sovrascritto -con `--hostname-override`) come nome dell'oggetto Nodo Kubernetes. Si noti che il nome del nodo Kubernetes deve +Il provider di cloud Baidu utilizza l'indirizzo IP privato del nodo (come determinato dal kubelet o sovrascritto +con `--hostname-override`) come nome dell'oggetto Nodo Kubernetes. Si noti che il nome del nodo Kubernetes deve corrispondere all'IP privato VM di Baidu. diff --git a/content/it/docs/concepts/cluster-administration/cluster-administration-overview.md b/content/it/docs/concepts/cluster-administration/cluster-administration-overview.md index c2654fcf45..cd160cbdcc 100644 --- a/content/it/docs/concepts/cluster-administration/cluster-administration-overview.md +++ b/content/it/docs/concepts/cluster-administration/cluster-administration-overview.md @@ -20,9 +20,9 @@ Prima di scegliere una guida, ecco alcune considerazioni: - **Se si sta progettando per l'alta disponibilità**, impara a configurare [cluster in più zone](/docs/concepts/cluster-administration/federation/). - Utilizzerai **un cluster di Kubernetes ospitato**, come [Motore di Google Kubernetes](https://cloud.google.com/kubernetes-engine/) o **che ospita il tuo cluster**? - Il tuo cluster sarà **on-premises** o **nel cloud (IaaS)**? Kubernetes non supporta direttamente i cluster ibridi. Invece, puoi impostare più cluster. - - **Se stai configurando Kubernetes on-premises**, considera quale [modello di rete](/docs/concepts/cluster-administration/networking/) si adatti meglio. + - **Se stai configurando Kubernetes on-premises**, considera quale [modello di rete](/docs/concepts/cluster-administration/networking/) si adatti meglio. - Eseguirai Kubernetes su **hardware "bare metal"** o su **macchine virtuali (VM)**? - - Vuoi **solo eseguire un cluster**, oppure ti aspetti di fare **lo sviluppo attivo del codice del progetto di Kubernetes**? + - Vuoi **solo eseguire un cluster**, oppure ti aspetti di fare **lo sviluppo attivo del codice del progetto di Kubernetes**? In quest'ultimo caso, scegli una distribuzione sviluppata attivamente. Alcune distribuzioni utilizzano solo versioni binarie, ma offrono una maggiore varietà di scelte - Familiarizzare con i [componenti](/docs/admin/cluster-components/) necessari per eseguire un cluster. diff --git a/content/it/docs/concepts/cluster-administration/controller-metrics.md b/content/it/docs/concepts/cluster-administration/controller-metrics.md index c38d0840cd..666b6023de 100644 --- a/content/it/docs/concepts/cluster-administration/controller-metrics.md +++ b/content/it/docs/concepts/cluster-administration/controller-metrics.md @@ -13,13 +13,13 @@ il responsabile del controller. ## Cosa sono le metriche del controller -Le metriche del controller forniscono informazioni importanti sulle prestazioni del controller. Queste metriche -includono le comuni metriche di runtime del linguaggio Go, come il conteggio go_routine e le metriche specifiche del -controller come latenze delle richieste etcd o latenze API Cloudprovider (AWS, GCE, OpenStack) che possono essere +Le metriche del controller forniscono informazioni importanti sulle prestazioni del controller. Queste metriche +includono le comuni metriche di runtime del linguaggio Go, come il conteggio go_routine e le metriche specifiche del +controller come latenze delle richieste etcd o latenze API Cloudprovider (AWS, GCE, OpenStack) che possono essere utilizzate per valutare la salute di un cluster. -A partire da Kubernetes 1.7, le metriche dettagliate di Cloudprovider sono disponibili per le operazioni di archiviazione -per GCE, AWS, Vsphere e OpenStack. Queste metriche possono essere utilizzate per monitorare lo stato delle operazioni +A partire da Kubernetes 1.7, le metriche dettagliate di Cloudprovider sono disponibili per le operazioni di archiviazione +per GCE, AWS, Vsphere e OpenStack. Queste metriche possono essere utilizzate per monitorare lo stato delle operazioni di volume persistenti. Ad esempio, per GCE queste metriche sono chiamate: diff --git a/content/it/docs/concepts/cluster-administration/kubelet-garbage-collection.md b/content/it/docs/concepts/cluster-administration/kubelet-garbage-collection.md index f787519141..976e64cc95 100644 --- a/content/it/docs/concepts/cluster-administration/kubelet-garbage-collection.md +++ b/content/it/docs/concepts/cluster-administration/kubelet-garbage-collection.md @@ -6,11 +6,11 @@ weight: 70 --- {{% capture overview %}} -La garbage collection è una funzione utile di kubelet che pulisce le immagini inutilizzate e i contenitori inutilizzati. -Kubelet eseguirà la raccolta dei rifiuti per i contenitori ogni minuto e la raccolta dei dati inutili per le immagini +La garbage collection è una funzione utile di kubelet che pulisce le immagini inutilizzate e i contenitori inutilizzati. +Kubelet eseguirà la raccolta dei rifiuti per i contenitori ogni minuto e la raccolta dei dati inutili per le immagini ogni cinque minuti. -Gli strumenti di garbage collection esterni non sono raccomandati in quanto questi strumenti possono potenzialmente +Gli strumenti di garbage collection esterni non sono raccomandati in quanto questi strumenti possono potenzialmente interrompere il comportamento di kubelet rimuovendo i contenitori che si prevede esistano. {{% /capture %}} @@ -34,18 +34,18 @@ soglia è stata soddisfatta. ## Container Collection -La politica per i contenitori di garbage collection considera tre variabili definite dall'utente. `MinAge` è l'età minima -in cui un contenitore può essere raccolto dalla spazzatura. `MaxPerPodContainer` è il numero massimo di contenitori morti -ogni singolo la coppia pod (UID, nome contenitore) può avere. `MaxContainers` è il numero massimo di contenitori morti -totali. Queste variabili possono essere disabilitate individualmente impostando `MinAge` a zero e impostando `MaxPerPodContainer` +La politica per i contenitori di garbage collection considera tre variabili definite dall'utente. `MinAge` è l'età minima +in cui un contenitore può essere raccolto dalla spazzatura. `MaxPerPodContainer` è il numero massimo di contenitori morti +ogni singolo la coppia pod (UID, nome contenitore) può avere. `MaxContainers` è il numero massimo di contenitori morti +totali. Queste variabili possono essere disabilitate individualmente impostando `MinAge` a zero e impostando `MaxPerPodContainer` e `MaxContainers` rispettivamente a meno di zero. -Kubelet agirà su contenitori non identificati, cancellati o al di fuori dei limiti impostati dalle bandiere -precedentemente menzionate. I contenitori più vecchi saranno generalmente rimossi per primi. `MaxPerPodContainer` -e `MaxContainer` possono potenzialmente entrare in conflitto l'uno con l'altro in situazioni in cui il mantenimento del -numero massimo di contenitori per pod (`MaxPerPodContainer`) non rientra nell'intervallo consentito di contenitori morti -globali (` MaxContainers`). `MaxPerPodContainer` verrebbe regolato in questa situazione: uno scenario peggiore sarebbe -quello di eseguire il downgrade di` MaxPerPodContainer` su 1 e rimuovere i contenitori più vecchi. Inoltre, i +Kubelet agirà su contenitori non identificati, cancellati o al di fuori dei limiti impostati dalle bandiere +precedentemente menzionate. I contenitori più vecchi saranno generalmente rimossi per primi. `MaxPerPodContainer` +e `MaxContainer` possono potenzialmente entrare in conflitto l'uno con l'altro in situazioni in cui il mantenimento del +numero massimo di contenitori per pod (`MaxPerPodContainer`) non rientra nell'intervallo consentito di contenitori morti +globali (` MaxContainers`). `MaxPerPodContainer` verrebbe regolato in questa situazione: uno scenario peggiore sarebbe +quello di eseguire il downgrade di` MaxPerPodContainer` su 1 e rimuovere i contenitori più vecchi. Inoltre, i contenitori di proprietà dei pod che sono stati cancellati vengono rimossi una volta che sono più vecchi di "MinAge". I contenitori che non sono gestiti da Kubelet non sono soggetti alla garbage collection del contenitore. diff --git a/content/it/docs/concepts/cluster-administration/manage-deployment.md b/content/it/docs/concepts/cluster-administration/manage-deployment.md index 33f3cb7ec2..4f4d3dae50 100644 --- a/content/it/docs/concepts/cluster-administration/manage-deployment.md +++ b/content/it/docs/concepts/cluster-administration/manage-deployment.md @@ -6,9 +6,9 @@ weight: 40 {{% capture overview %}} -Hai distribuito la tua applicazione e l'hai esposta tramite un servizio. Ora cosa? Kubernetes fornisce una serie di -strumenti per aiutarti a gestire la distribuzione delle applicazioni, compreso il ridimensionamento e l'aggiornamento. -Tra le caratteristiche che discuteremo in modo più approfondito ci sono [file di configurazione](/docs/concepts/configuration/overview/) +Hai distribuito la tua applicazione e l'hai esposta tramite un servizio. Ora cosa? Kubernetes fornisce una serie di +strumenti per aiutarti a gestire la distribuzione delle applicazioni, compreso il ridimensionamento e l'aggiornamento. +Tra le caratteristiche che discuteremo in modo più approfondito ci sono [file di configurazione](/docs/concepts/configuration/overview/) e [labels](/docs/concepts/overview/working-with-objects/labels/). {{% /capture %}} @@ -187,9 +187,9 @@ guestbook-redis-slave-qgazl 1/1 Running 0 3m ## Distribuzioni canarie -Un altro scenario in cui sono necessarie più etichette è quello di distinguere distribuzioni di diverse versioni o -configurazioni dello stesso componente. È prassi comune distribuire un * canarino * di una nuova versione -dell'applicazione (specificata tramite il tag immagine nel modello pod) parallelamente alla versione precedente in +Un altro scenario in cui sono necessarie più etichette è quello di distinguere distribuzioni di diverse versioni o +configurazioni dello stesso componente. È prassi comune distribuire un * canarino * di una nuova versione +dell'applicazione (specificata tramite il tag immagine nel modello pod) parallelamente alla versione precedente in modo che la nuova versione possa ricevere il traffico di produzione in tempo reale prima di distribuirlo completamente. Ad esempio, puoi usare un'etichetta `track` per differenziare le diverse versioni. @@ -208,7 +208,7 @@ La versione stabile e primaria avrebbe un'etichetta `track` con valore come` sta image: gb-frontend:v3 ``` -e quindi puoi creare una nuova versione del frontend del guestbook che porta l'etichetta `track` con un valore diverso +e quindi puoi creare una nuova versione del frontend del guestbook che porta l'etichetta `track` con un valore diverso (ad esempio` canary`), in modo che due gruppi di pod non si sovrappongano: ```yaml @@ -223,8 +223,8 @@ e quindi puoi creare una nuova versione del frontend del guestbook che porta l'e image: gb-frontend:v4 ``` -Il servizio di frontend coprirebbe entrambe le serie di repliche selezionando il sottoinsieme comune delle loro -etichette (ad esempio omettendo l'etichetta `track`), in modo che il traffico venga reindirizzato ad entrambe le +Il servizio di frontend coprirebbe entrambe le serie di repliche selezionando il sottoinsieme comune delle loro +etichette (ad esempio omettendo l'etichetta `track`), in modo che il traffico venga reindirizzato ad entrambe le applicazioni: ```yaml @@ -234,16 +234,16 @@ applicazioni: ``` 452/5000 -È possibile modificare il numero di repliche delle versioni stable e canary per determinare il rapporto tra ciascuna -versione che riceverà il traffico di produzione live (in questo caso, 3: 1). Una volta che sei sicuro, puoi aggiornare +È possibile modificare il numero di repliche delle versioni stable e canary per determinare il rapporto tra ciascuna +versione che riceverà il traffico di produzione live (in questo caso, 3: 1). Una volta che sei sicuro, puoi aggiornare la traccia stabile alla nuova versione dell'applicazione e rimuovere quella canarino. Per un esempio più concreto, controlla il [tutorial di distribuzione di Ghost](https://github.com/kelseyhightower/talks/tree/master/kubecon-eu-2016/demo#deploy-a-canary). ## Updating labels -A volte i pod esistenti e altre risorse devono essere rinominati prima di creare nuove risorse. Questo può essere fatto -con l'etichetta `kubectl`. Ad esempio, se desideri etichettare tutti i tuoi pod nginx come livello frontend, esegui +A volte i pod esistenti e altre risorse devono essere rinominati prima di creare nuove risorse. Questo può essere fatto +con l'etichetta `kubectl`. Ad esempio, se desideri etichettare tutti i tuoi pod nginx come livello frontend, esegui semplicemente: ```shell @@ -253,7 +253,7 @@ pod/my-nginx-2035384211-u2c7e labeled pod/my-nginx-2035384211-u3t6x labeled ``` -Questo prima filtra tutti i pod con l'etichetta "app = nginx", quindi li etichetta con il "tier = fe". Per vedere i pod +Questo prima filtra tutti i pod con l'etichetta "app = nginx", quindi li etichetta con il "tier = fe". Per vedere i pod appena etichettati, esegui: ```shell @@ -267,13 +267,13 @@ my-nginx-2035384211-u3t6x 1/1 Running 0 23m fe questo produce tutti i pod "app = nginx", con un'ulteriore colonna di etichette del livello dei pod (specificata con `-L` o` --label-columns`). -Per ulteriori informazioni, consultare [labels](/docs/concepts/overview/working-with-objects/labels/) e +Per ulteriori informazioni, consultare [labels](/docs/concepts/overview/working-with-objects/labels/) e [kubectl label](/docs/reference/generated/kubectl/kubectl-commands/#label). ## Aggiornare annotazioni -A volte vorresti allegare annotazioni alle risorse. Le annotazioni sono metadati arbitrari non identificativi per il -recupero da parte di client API come strumenti, librerie, ecc. Questo può essere fatto con `kubectl annotate`. Per +A volte vorresti allegare annotazioni alle risorse. Le annotazioni sono metadati arbitrari non identificativi per il +recupero da parte di client API come strumenti, librerie, ecc. Questo può essere fatto con `kubectl annotate`. Per esempio: ```shell @@ -287,12 +287,12 @@ metadata: ... ``` -Per ulteriori informazioni, consultare il documento [annotazioni](/docs/concepts/overview/working-with-objects/annotations/) +Per ulteriori informazioni, consultare il documento [annotazioni](/docs/concepts/overview/working-with-objects/annotations/) e [kubectl annotate](/docs/reference/generated/kubectl/kubectl-commands/#annotate). ## Ridimensionamento dell'applicazione -Quando si carica o si riduce la richiesta, è facile ridimensionare con `kubectl`. Ad esempio, per ridurre il numero di +Quando si carica o si riduce la richiesta, è facile ridimensionare con `kubectl`. Ad esempio, per ridurre il numero di repliche nginx da 3 a 1, fare: ```shell @@ -318,7 +318,7 @@ horizontalpodautoscaler.autoscaling/my-nginx autoscaled Ora le repliche di nginx verranno ridimensionate automaticamente in base alle esigenze. Per maggiori informazioni, vedi [scala kubectl](/docs/reference/generated/kubectl/kubectl-commands/#scale), -[kubectl autoscale](/docs/reference/generated/kubectl/kubectl-commands/#autoscale) e documento +[kubectl autoscale](/docs/reference/generated/kubectl/kubectl-commands/#autoscale) e documento [orizzontale pod autoscaler](/docs/tasks/run-application/horizontal-pod-autoscale/). ## Aggiornamenti sul posto delle risorse @@ -327,13 +327,13 @@ A volte è necessario apportare aggiornamenti stretti e senza interruzioni alle ### kubectl apply -Si consiglia di mantenere un set di file di configurazione nel controllo del codice sorgente (vedere -[configurazione come codice](http://martinfowler.com/bliki/InfrastructureAsCode.html)), in modo che possano essere -mantenuti e versionati insieme al codice per le risorse che configurano. Quindi, puoi usare +Si consiglia di mantenere un set di file di configurazione nel controllo del codice sorgente (vedere +[configurazione come codice](http://martinfowler.com/bliki/InfrastructureAsCode.html)), in modo che possano essere +mantenuti e versionati insieme al codice per le risorse che configurano. Quindi, puoi usare [`kubectl apply`](/docs/reference/generated/kubectl/kubectl-commands/#apply) per inviare le modifiche alla configurazione nel cluster. -Questo comando confronterà la versione della configurazione che stai spingendo con la versione precedente e applicherà +Questo comando confronterà la versione della configurazione che stai spingendo con la versione precedente e applicherà le modifiche che hai apportato, senza sovrascrivere le modifiche automatiche alle proprietà che non hai specificato. ```shell @@ -341,18 +341,18 @@ $ kubectl apply -f https://k8s.io/examples/application/nginx/nginx-deployment.ya deployment.apps/my-nginx configured ``` -Si noti che `kubectl apply` allega un'annotazione alla risorsa per determinare le modifiche alla configurazione -dall'invocazione precedente. Quando viene invocato, `kubectl apply` fa una differenza a tre tra la configurazione -precedente, l'input fornito e la configurazione corrente della risorsa, al fine di determinare come modificare la +Si noti che `kubectl apply` allega un'annotazione alla risorsa per determinare le modifiche alla configurazione +dall'invocazione precedente. Quando viene invocato, `kubectl apply` fa una differenza a tre tra la configurazione +precedente, l'input fornito e la configurazione corrente della risorsa, al fine di determinare come modificare la risorsa. -Attualmente, le risorse vengono create senza questa annotazione, quindi la prima chiamata di `kubectl apply` ricadrà su -una differenza a due vie tra l'input fornito e la configurazione corrente della risorsa. Durante questa prima chiamata, -non è in grado di rilevare l'eliminazione delle proprietà impostate al momento della creazione della risorsa. Per questo +Attualmente, le risorse vengono create senza questa annotazione, quindi la prima chiamata di `kubectl apply` ricadrà su +una differenza a due vie tra l'input fornito e la configurazione corrente della risorsa. Durante questa prima chiamata, +non è in grado di rilevare l'eliminazione delle proprietà impostate al momento della creazione della risorsa. Per questo motivo, non li rimuoverà. -Tutte le chiamate successive a `kubectl apply`, e altri comandi che modificano la configurazione, come `kubectl replace` -e `kubectl edit`, aggiorneranno l'annotazione, consentendo le successive chiamate a` kubectl apply` per rilevare ed +Tutte le chiamate successive a `kubectl apply`, e altri comandi che modificano la configurazione, come `kubectl replace` +e `kubectl edit`, aggiorneranno l'annotazione, consentendo le successive chiamate a` kubectl apply` per rilevare ed eseguire cancellazioni usando un tre via diff. {{< note >}} @@ -367,7 +367,7 @@ In alternativa, puoi anche aggiornare le risorse con `kubectl edit`: $ kubectl edit deployment/my-nginx ``` -Questo equivale a prima "get` la risorsa, modificarla nell'editor di testo e quindi" applicare "la risorsa con la +Questo equivale a prima "get` la risorsa, modificarla nell'editor di testo e quindi" applicare "la risorsa con la versione aggiornata: ```shell @@ -379,7 +379,7 @@ deployment.apps/my-nginx configured $ rm /tmp/nginx.yaml ``` -Questo ti permette di fare più cambiamenti significativi più facilmente. Nota che puoi specificare l'editor con le +Questo ti permette di fare più cambiamenti significativi più facilmente. Nota che puoi specificare l'editor con le variabili di ambiente `EDITOR` o` KUBE_EDITOR`. Per ulteriori informazioni, consultare il documento [kubectl edit](/docs/reference/generated/kubectl/kubectl-commands/#edit). @@ -396,9 +396,9 @@ and ## Disruptive updates 375/5000 -In alcuni casi, potrebbe essere necessario aggiornare i campi di risorse che non possono essere aggiornati una volta -inizializzati, oppure si può semplicemente voler fare immediatamente una modifica ricorsiva, come per esempio correggere -i pod spezzati creati da una distribuzione. Per cambiare tali campi, usa `replace --force`, che elimina e ricrea la +In alcuni casi, potrebbe essere necessario aggiornare i campi di risorse che non possono essere aggiornati una volta +inizializzati, oppure si può semplicemente voler fare immediatamente una modifica ricorsiva, come per esempio correggere +i pod spezzati creati da una distribuzione. Per cambiare tali campi, usa `replace --force`, che elimina e ricrea la risorsa. In questo caso, puoi semplicemente modificare il tuo file di configurazione originale: ```shell @@ -409,12 +409,12 @@ deployment.apps/my-nginx replaced ## Aggiornamento dell'applicazione senza un'interruzione del servizio -A un certo punto, alla fine sarà necessario aggiornare l'applicazione distribuita, in genere specificando una nuova -immagine o un tag immagine, come nello scenario di distribuzione canarino precedente. `kubectl` supporta diverse +A un certo punto, alla fine sarà necessario aggiornare l'applicazione distribuita, in genere specificando una nuova +immagine o un tag immagine, come nello scenario di distribuzione canarino precedente. `kubectl` supporta diverse operazioni di aggiornamento, ognuna delle quali è applicabile a diversi scenari. -Ti guideremo attraverso come creare e aggiornare le applicazioni con le distribuzioni. Se l'applicazione distribuita è -gestita dai controller di replica, dovresti leggere +Ti guideremo attraverso come creare e aggiornare le applicazioni con le distribuzioni. Se l'applicazione distribuita è +gestita dai controller di replica, dovresti leggere [come usare `kubectl rolling-update`](/docs/tasks/run-application/rolling-update-replication-controller/). Diciamo che stavi usando la versione 1.7.9 di nginx: @@ -424,16 +424,16 @@ $ kubectl run my-nginx --image=nginx:1.7.9 --replicas=3 deployment.apps/my-nginx created ``` -Per aggiornare alla versione 1.9.1, cambia semplicemente `.spec.template.spec.containers [0] .image` da `nginx: 1.7.9` +Per aggiornare alla versione 1.9.1, cambia semplicemente `.spec.template.spec.containers [0] .image` da `nginx: 1.7.9` a `nginx: 1.9.1`, con i comandi kubectl che abbiamo imparato sopra. ```shell $ kubectl edit deployment/my-nginx ``` -Questo è tutto! La distribuzione aggiornerà in modo dichiarativo l'applicazione nginx distribuita progressivamente -dietro la scena. Garantisce che solo un certo numero di vecchie repliche potrebbe essere inattivo mentre vengono -aggiornate e solo un certo numero di nuove repliche può essere creato sopra il numero desiderato di pod. Per ulteriori +Questo è tutto! La distribuzione aggiornerà in modo dichiarativo l'applicazione nginx distribuita progressivamente +dietro la scena. Garantisce che solo un certo numero di vecchie repliche potrebbe essere inattivo mentre vengono +aggiornate e solo un certo numero di nuove repliche può essere creato sopra il numero desiderato di pod. Per ulteriori informazioni su di esso, visitare [Pagina di distribuzione](/docs/concepts/workloads/controller/deployment/). {{% /capture %}} diff --git a/content/it/docs/concepts/cluster-administration/networking.md b/content/it/docs/concepts/cluster-administration/networking.md index 697328535f..2888511489 100644 --- a/content/it/docs/concepts/cluster-administration/networking.md +++ b/content/it/docs/concepts/cluster-administration/networking.md @@ -5,7 +5,7 @@ weight: 50 --- {{% capture overview %}} -Il networking è una parte centrale di Kubernetes, ma può essere difficile capire esattamente come dovrebbe funzionare. +Il networking è una parte centrale di Kubernetes, ma può essere difficile capire esattamente come dovrebbe funzionare. Ci sono 4 reti distinte problemi da affrontare: 1. Comunicazioni container-to-container altamente accoppiate: questo è risolto da @@ -71,35 +71,35 @@ cieco all'esistenza o alla non esistenza dei porti di accoglienza. ## Come implementare il modello di rete di Kubernetes -Ci sono diversi modi in cui questo modello di rete può essere implementato. Questo il documento non è uno studio +Ci sono diversi modi in cui questo modello di rete può essere implementato. Questo il documento non è uno studio esaustivo dei vari metodi, ma si spera che serva come introduzione a varie tecnologie e serve da punto di partenza. Le seguenti opzioni di networking sono ordinate alfabeticamente - l'ordine no implica uno stato preferenziale. ### ACI -[Cisco Application Centric Infrastructure](https://www.cisco.com/c/en/us/solutions/data-center-virtualization/application-centric-infrastructure/index.html) +[Cisco Application Centric Infrastructure](https://www.cisco.com/c/en/us/solutions/data-center-virtualization/application-centric-infrastructure/index.html) offers an integrated overlay and underlay SDN solution that supports containers, virtual machines, and bare metal -servers. [ACI](https://www.github.com/noironetworks/aci-containers) provides container networking integration for ACI. +servers. [ACI](https://www.github.com/noironetworks/aci-containers) provides container networking integration for ACI. An overview of the integration is provided [here](https://www.cisco.com/c/dam/en/us/solutions/collateral/data-center-virtualization/application-centric-infrastructure/solution-overview-c22-739493.pdf). ### AOS da Apstra -[AOS](http://www.apstra.com/products/aos/) è un sistema di rete basato sull'intento che crea e gestisce ambienti di -data center complessi da una semplice piattaforma integrata. AOS sfrutta un design distribuito altamente scalabile per +[AOS](http://www.apstra.com/products/aos/) è un sistema di rete basato sull'intento che crea e gestisce ambienti di +data center complessi da una semplice piattaforma integrata. AOS sfrutta un design distribuito altamente scalabile per eliminare le interruzioni di rete riducendo al minimo i costi. -Il progetto di riferimento AOS attualmente supporta gli host connessi Layer-3 che eliminano i problemi di commutazione -Layer-2 legacy. Questi host Layer-3 possono essere server Linux (Debian, Ubuntu, CentOS) che creano relazioni vicine -BGP direttamente con gli switch top of rack (TOR). AOS automatizza le adiacenze di routing e quindi fornisce un +Il progetto di riferimento AOS attualmente supporta gli host connessi Layer-3 che eliminano i problemi di commutazione +Layer-2 legacy. Questi host Layer-3 possono essere server Linux (Debian, Ubuntu, CentOS) che creano relazioni vicine +BGP direttamente con gli switch top of rack (TOR). AOS automatizza le adiacenze di routing e quindi fornisce un controllo a grana fine sulle iniezioni di integrità del percorso (RHI) comuni in una distribuzione di Kubernetes. -AOS dispone di un ricco set di endpoint REST API che consentono a Kubernetes di modificare rapidamente i criteri di -rete in base ai requisiti dell'applicazione. Ulteriori miglioramenti integreranno il modello AOS Graph utilizzato per -la progettazione della rete con il provisioning del carico di lavoro, consentendo un sistema di gestione end-to-end per +AOS dispone di un ricco set di endpoint REST API che consentono a Kubernetes di modificare rapidamente i criteri di +rete in base ai requisiti dell'applicazione. Ulteriori miglioramenti integreranno il modello AOS Graph utilizzato per +la progettazione della rete con il provisioning del carico di lavoro, consentendo un sistema di gestione end-to-end per cloud privati ​​e pubblici. -AOS supporta l'utilizzo di apparecchiature di produttori comuni di produttori quali Cisco, Arista, Dell, Mellanox, HPE +AOS supporta l'utilizzo di apparecchiature di produttori comuni di produttori quali Cisco, Arista, Dell, Mellanox, HPE e un gran numero di sistemi white-box e sistemi operativi di rete aperti come Microsoft SONiC, Dell OPX e Cumulus Linux. I dettagli su come funziona il sistema AOS sono disponibili qui: http://www.apstra.com/products/how-it-works/ @@ -121,11 +121,11 @@ indirizzamento. ### CNI-Genie from Huawei -[CNI-Genie](https://github.com/Huawei-PaaS/CNI-Genie) è un plugin CNI che consente a Kubernetes -di [avere simultaneamente accesso a diverse implementazioni](https://github.com/Huawei-PaaS/CNI-Genie/blob/master/docs/multiple-cni-plugins/README.md#what-cni-genie-feature-1-multiple-cni-plugins-enables) -del [modello di rete Kubernetes](https://git.k8s.io/website/docs/concepts/cluster-administration/networking.md#kubernetes-model) in runtime. -Ciò include qualsiasi implementazione che funziona come un [plugin CNI](https://github.com/containernetworking/cni#3rd-party-plugins), -come [Flannel](https://github.com/coreos/flannel#flanella), [Calico](http://docs.projectcalico.org/), +[CNI-Genie](https://github.com/Huawei-PaaS/CNI-Genie) è un plugin CNI che consente a Kubernetes +di [avere simultaneamente accesso a diverse implementazioni](https://github.com/Huawei-PaaS/CNI-Genie/blob/master/docs/multiple-cni-plugins/README.md#what-cni-genie-feature-1-multiple-cni-plugins-enables) +del [modello di rete Kubernetes](https://git.k8s.io/website/docs/concepts/cluster-administration/networking.md#kubernetes-model) in runtime. +Ciò include qualsiasi implementazione che funziona come un [plugin CNI](https://github.com/containernetworking/cni#3rd-party-plugins), +come [Flannel](https://github.com/coreos/flannel#flanella), [Calico](http://docs.projectcalico.org/), [Romana](http://romana.io), [Weave-net](https://www.weave.works/products/tessere-net/). CNI-Genie supporta anche [assegnando più indirizzi IP a un pod](https://github.com/Huawei-PaaS/CNI-Genie/blob/master/docs/multiple-ips/README.md#feature-2-extension-cni-genie-multiple-ip-indirizzi-per-pod), ciascuno da un diverso plugin CNI. @@ -151,15 +151,15 @@ complessità della rete richiesta per implementare Kubernetes su larga scala all 226/5000 -[Contiv](https://github.com/contiv/netplugin) fornisce un networking configurabile (nativo l3 usando BGP, +[Contiv](https://github.com/contiv/netplugin) fornisce un networking configurabile (nativo l3 usando BGP, overlay usando vxlan, classic l2 o Cisco-SDN / ACI) per vari casi d'uso. [Contiv](http://contiv.io) è tutto aperto. ### Contrail / Tungsten Fabric -[Contrail](http://www.juniper.net/us/en/products-services/sdn/contrail/contrail-networking/), basato su -[Tungsten Fabric](https://tungsten.io), è un virtualizzazione della rete e piattaforma di gestione delle -policy realmente aperte e multi-cloud. Contrail e Tungsten Fabric sono integrati con vari sistemi di -orchestrazione come Kubernetes, OpenShift, OpenStack e Mesos e forniscono diverse modalità di isolamento +[Contrail](http://www.juniper.net/us/en/products-services/sdn/contrail/contrail-networking/), basato su +[Tungsten Fabric](https://tungsten.io), è un virtualizzazione della rete e piattaforma di gestione delle +policy realmente aperte e multi-cloud. Contrail e Tungsten Fabric sono integrati con vari sistemi di +orchestrazione come Kubernetes, OpenShift, OpenStack e Mesos e forniscono diverse modalità di isolamento per macchine virtuali, contenitori / pod e carichi di lavoro bare metal. ### DANM @@ -176,14 +176,14 @@ Con questo set di strumenti DANM è in grado di fornire più interfacce di rete ### Flannel -[Flannel](https://github.com/coreos/flannel#flannel) è un overlay molto semplice rete che soddisfa i requisiti di +[Flannel](https://github.com/coreos/flannel#flannel) è un overlay molto semplice rete che soddisfa i requisiti di Kubernetes. Molti le persone hanno riportato il successo con Flannel e Kubernetes. ### Google Compute Engine (GCE) -Per gli script di configurazione del cluster di Google Compute Engine, -[avanzato routing](https://cloud.google.com/vpc/docs/routes) è usato per assegna a ciascuna VM una sottorete -(l'impostazione predefinita è `/ 24` - 254 IP). Qualsiasi traffico vincolato per questo la sottorete verrà instradata +Per gli script di configurazione del cluster di Google Compute Engine, +[avanzato routing](https://cloud.google.com/vpc/docs/routes) è usato per assegna a ciascuna VM una sottorete +(l'impostazione predefinita è `/ 24` - 254 IP). Qualsiasi traffico vincolato per questo la sottorete verrà instradata direttamente alla VM dal fabric di rete GCE. Questo è dentro aggiunta all'indirizzo IP "principale" assegnato alla VM, a cui è stato assegnato NAT accesso a Internet in uscita. Un bridge linux (chiamato `cbr0`) è configurato per esistere su quella sottorete, e viene passato al flag `--bridge` della finestra mobile. @@ -196,11 +196,11 @@ DOCKER_OPTS="--bridge=cbr0 --iptables=false --ip-masq=false" Questo bridge è creato da Kubelet (controllato da `--network-plugin = kubenet` flag) in base al `Nodo` .spec.podCIDR`. -Docker ora assegna gli IP dal blocco `cbr-cidr`. I contenitori possono raggiungere l'un l'altro e `Nodi` sul +Docker ora assegna gli IP dal blocco `cbr-cidr`. I contenitori possono raggiungere l'un l'altro e `Nodi` sul ponte` cbr0`. Questi IP sono tutti instradabili all'interno della rete del progetto GCE. -GCE non sa nulla di questi IP, quindi non lo farà loro per il traffico internet in uscita. Per ottenere ciò viene -utilizzata una regola iptables masquerade (aka SNAT - per far sembrare che i pacchetti provengano dal `Node` stesso) +GCE non sa nulla di questi IP, quindi non lo farà loro per il traffico internet in uscita. Per ottenere ciò viene +utilizzata una regola iptables masquerade (aka SNAT - per far sembrare che i pacchetti provengano dal `Node` stesso) traffico che è vincolato per IP al di fuori della rete del progetto GCE (10.0.0.0/8). ```shell @@ -219,25 +219,25 @@ traffico verso internet. ### Jaguar -[Jaguar](https://gitlab.com/sdnlab/jaguar) è una soluzione open source per la rete di Kubernetes basata -su OpenDaylight. Jaguar fornisce una rete overlay utilizzando vxlan e Jaguar. CNIPlugin fornisce un indirizzo +[Jaguar](https://gitlab.com/sdnlab/jaguar) è una soluzione open source per la rete di Kubernetes basata +su OpenDaylight. Jaguar fornisce una rete overlay utilizzando vxlan e Jaguar. CNIPlugin fornisce un indirizzo IP per pod. ### Knitter 363/5000 -[Knitter](https://github.com/ZTE/Knitter/) è una soluzione di rete che supporta più reti in Kubernetes. -Fornisce la capacità di gestione dei titolari e gestione della rete. Knitter include una serie di soluzioni -di rete container NFV end-to-end oltre a più piani di rete, come mantenere l'indirizzo IP per le applicazioni, +[Knitter](https://github.com/ZTE/Knitter/) è una soluzione di rete che supporta più reti in Kubernetes. +Fornisce la capacità di gestione dei titolari e gestione della rete. Knitter include una serie di soluzioni +di rete container NFV end-to-end oltre a più piani di rete, come mantenere l'indirizzo IP per le applicazioni, la migrazione degli indirizzi IP, ecc. ### Kube-router 430/5000 -[Kube-router](https://github.com/cloudnativelabs/kube-router) è una soluzione di rete sviluppata appositamente -per Kubernetes che mira a fornire alte prestazioni e semplicità operativa. Kube-router fornisce un proxy di -servizio basato su Linux [LVS / IPVS](http://www.linuxvirtualserver.org/software/ipvs.html), una soluzione di -rete pod-to-pod basata sul kernel di inoltro del kernel Linux senza sovrapposizioni, e il sistema di sicurezza +[Kube-router](https://github.com/cloudnativelabs/kube-router) è una soluzione di rete sviluppata appositamente +per Kubernetes che mira a fornire alte prestazioni e semplicità operativa. Kube-router fornisce un proxy di +servizio basato su Linux [LVS / IPVS](http://www.linuxvirtualserver.org/software/ipvs.html), una soluzione di +rete pod-to-pod basata sul kernel di inoltro del kernel Linux senza sovrapposizioni, e il sistema di sicurezza della politica di rete basato su iptables / ipset. ### L2 networks and linux bridging @@ -254,41 +254,41 @@ Lars Kellogg-Stedman. ### Multus (a Multi Network plugin) -[Multus](https://github.com/Intel-Corp/multus-cni) è un plugin Multi CNI per supportare la funzionalità Multi +[Multus](https://github.com/Intel-Corp/multus-cni) è un plugin Multi CNI per supportare la funzionalità Multi Networking in Kubernetes utilizzando oggetti di rete basati su CRD in Kubernetes. -Multus supporta tutti i [plug-in di riferimento](https://github.com/containernetworking/plugins) -(ad esempio [Flannel](https://github.com/containernetworking/plugins/tree/master/plugins/meta/flannel), -[DHCP](https://github.com/containernetworking/plugins/tree/master/plugins/ipam/dhcp), -[Macvlan](https://github.com/containernetworking/plugins/tree/master/plugins/main/macvlan)) che implementano -le specifiche CNI e i plugin di terze parti (ad esempio [Calico](https://github.com/projectcalico/cni-plugin), -[Weave](https://github.com/weaveworks/weave) ), [Cilium](https://github.com/cilium/cilium), -[Contiv](https://github.com/contiv/netplugin)). Oltre a ciò, Multus supporta -[SRIOV](https://github.com/hustcat/sriov-cni), [DPDK](https://github.com/Intel-Corp/sriov-cni), -[OVS- DPDK e VPP](https://github.com/intel/vhost-user-net-plugin) carichi di lavoro in Kubernetes con applicazioni +Multus supporta tutti i [plug-in di riferimento](https://github.com/containernetworking/plugins) +(ad esempio [Flannel](https://github.com/containernetworking/plugins/tree/master/plugins/meta/flannel), +[DHCP](https://github.com/containernetworking/plugins/tree/master/plugins/ipam/dhcp), +[Macvlan](https://github.com/containernetworking/plugins/tree/master/plugins/main/macvlan)) che implementano +le specifiche CNI e i plugin di terze parti (ad esempio [Calico](https://github.com/projectcalico/cni-plugin), +[Weave](https://github.com/weaveworks/weave) ), [Cilium](https://github.com/cilium/cilium), +[Contiv](https://github.com/contiv/netplugin)). Oltre a ciò, Multus supporta +[SRIOV](https://github.com/hustcat/sriov-cni), [DPDK](https://github.com/Intel-Corp/sriov-cni), +[OVS- DPDK e VPP](https://github.com/intel/vhost-user-net-plugin) carichi di lavoro in Kubernetes con applicazioni cloud native e basate su NFV in Kubernetes. ### NSX-T -[VMware NSX-T](https://docs.vmware.com/en/VMware-NSX-T/index.html) è una piattaforma di virtualizzazione e sicurezza -della rete. NSX-T può fornire la virtualizzazione di rete per un ambiente multi-cloud e multi-hypervisor ed è -focalizzato su architetture applicative emergenti e architetture con endpoint eterogenei e stack tecnologici. Oltre +[VMware NSX-T](https://docs.vmware.com/en/VMware-NSX-T/index.html) è una piattaforma di virtualizzazione e sicurezza +della rete. NSX-T può fornire la virtualizzazione di rete per un ambiente multi-cloud e multi-hypervisor ed è +focalizzato su architetture applicative emergenti e architetture con endpoint eterogenei e stack tecnologici. Oltre agli hypervisor vSphere, questi ambienti includono altri hypervisor come KVM, container e bare metal. -[Plug-in contenitore NSX-T (NCP)](https://docs.vmware.com/en/VMware-NSX-T/2.0/nsxt_20_ncp_kubernetes.pdf) fornisce -integrazione tra NSX-T e orchestratori di contenitori come Kubernetes, così come l'integrazione tra NSX-T e piattaforme +[Plug-in contenitore NSX-T (NCP)](https://docs.vmware.com/en/VMware-NSX-T/2.0/nsxt_20_ncp_kubernetes.pdf) fornisce +integrazione tra NSX-T e orchestratori di contenitori come Kubernetes, così come l'integrazione tra NSX-T e piattaforme CaaS / PaaS basate su container come Pivotal Container Service (PKS) e OpenShift. ### Nuage Networks VCS (Servizi cloud virtualizzati) -[Nuage](http://www.nuagenetworks.net) fornisce una piattaforma Software-Defined Networking (SDN) altamente scalabile -basata su policy. Nuage utilizza open source Open vSwitch per il piano dati insieme a un controller SDN ricco di +[Nuage](http://www.nuagenetworks.net) fornisce una piattaforma Software-Defined Networking (SDN) altamente scalabile +basata su policy. Nuage utilizza open source Open vSwitch per il piano dati insieme a un controller SDN ricco di funzionalità basato su standard aperti. -La piattaforma Nuage utilizza gli overlay per fornire una rete basata su policy senza soluzione di continuità tra i -Pod di Kubernetes e gli ambienti non Kubernetes (VM e server bare metal). Il modello di astrazione delle policy di -Nuage è stato progettato pensando alle applicazioni e semplifica la dichiarazione di policy a grana fine per le -applicazioni. Il motore di analisi in tempo reale della piattaforma consente la visibilità e il monitoraggio della +La piattaforma Nuage utilizza gli overlay per fornire una rete basata su policy senza soluzione di continuità tra i +Pod di Kubernetes e gli ambienti non Kubernetes (VM e server bare metal). Il modello di astrazione delle policy di +Nuage è stato progettato pensando alle applicazioni e semplifica la dichiarazione di policy a grana fine per le +applicazioni. Il motore di analisi in tempo reale della piattaforma consente la visibilità e il monitoraggio della sicurezza per le applicazioni Kubernetes. ### OpenVSwitch @@ -307,37 +307,37 @@ a [ovn-kubernetes](https://github.com/openvswitch/ovn-kubernetes). ### Progetto Calico -[Project Calico](http://docs.projectcalico.org/) è un provider di rete contenitore open source e +[Project Calico](http://docs.projectcalico.org/) è un provider di rete contenitore open source e motore di criteri di rete. -Calico offre una soluzione di rete e di rete altamente scalabile per il collegamento di pod Kubernetes basati sugli -stessi principi di rete IP di Internet, sia per Linux (open source) che per Windows (proprietario - disponibile da -[Tigera](https://www.tigera.io/essenziali/)). Calico può essere distribuito senza incapsulamento o sovrapposizioni per -fornire reti di data center ad alte prestazioni e su vasta scala. Calico fornisce inoltre una politica di sicurezza di +Calico offre una soluzione di rete e di rete altamente scalabile per il collegamento di pod Kubernetes basati sugli +stessi principi di rete IP di Internet, sia per Linux (open source) che per Windows (proprietario - disponibile da +[Tigera](https://www.tigera.io/essenziali/)). Calico può essere distribuito senza incapsulamento o sovrapposizioni per +fornire reti di data center ad alte prestazioni e su vasta scala. Calico fornisce inoltre una politica di sicurezza di rete basata su intere grane per i pod Kubernetes tramite il firewall distribuito. -Calico può anche essere eseguito in modalità di applicazione della policy insieme ad altre soluzioni di rete come +Calico può anche essere eseguito in modalità di applicazione della policy insieme ad altre soluzioni di rete come Flannel, alias [canal](https://github.com/tigera/canal) o native GCE, AWS o networking Azure. ### Romana -[Romana](http://romana.io) è una soluzione di automazione della sicurezza e della rete open source che consente di -distribuire Kubernetes senza una rete di overlay. Romana supporta Kubernetes -[Politica di rete](/docs/concepts/services-networking/network-policies/) per fornire isolamento tra gli spazi dei nomi +[Romana](http://romana.io) è una soluzione di automazione della sicurezza e della rete open source che consente di +distribuire Kubernetes senza una rete di overlay. Romana supporta Kubernetes +[Politica di rete](/docs/concepts/services-networking/network-policies/) per fornire isolamento tra gli spazi dei nomi di rete. ### Weave Net di Weaveworks -[Weave Net](https://www.weave.works/products/weave-net/) è un rete resiliente e semplice da usare per Kubernetes e le +[Weave Net](https://www.weave.works/products/weave-net/) è un rete resiliente e semplice da usare per Kubernetes e le sue applicazioni in hosting. Weave Net funziona come un plug-in [CNI](https://www.weave.works/docs/net/latest/cni-plugin/) -o stand-alone. In entrambe le versioni, non richiede alcuna configurazione o codice aggiuntivo per eseguire, e in +o stand-alone. In entrambe le versioni, non richiede alcuna configurazione o codice aggiuntivo per eseguire, e in entrambi i casi, la rete fornisce un indirizzo IP per pod, come è standard per Kubernetes. {{% /capture %}} {{% capture whatsnext %}} -Il progetto iniziale del modello di rete e la sua logica, e un po 'di futuro i piani sono descritti in maggior +Il progetto iniziale del modello di rete e la sua logica, e un po 'di futuro i piani sono descritti in maggior dettaglio nella [progettazione della rete documento](https://git.k8s.io/community/contributors/design-proposals/network/networking.md). {{% /capture %}} diff --git a/content/it/includes/federation-deprecation-warning-note.md b/content/it/includes/federation-deprecation-warning-note.md index 2d53cdaaf1..27c525642c 100644 --- a/content/it/includes/federation-deprecation-warning-note.md +++ b/content/it/includes/federation-deprecation-warning-note.md @@ -1,5 +1,5 @@ -L'uso di `Federation v1` è fortemente sconsigliato. `Federation V1` ha ormai raggiunto lo stato GA e non è più in +L'uso di `Federation v1` è fortemente sconsigliato. `Federation V1` ha ormai raggiunto lo stato GA e non è più in fase di sviluppo attivo. La documentazione è solo per scopi storici. -Per ulteriori informazioni, il seguente link +Per ulteriori informazioni, il seguente link [Kubernetes Federation v2](https://github.com/kubernetes-sigs/federation-v2). From 37137dadaf2acd80c9355bacb1597ffff4731956 Mon Sep 17 00:00:00 2001 From: xieyanker Date: Fri, 14 Feb 2020 10:22:17 +0800 Subject: [PATCH 027/111] fix format error (#19118) --- content/zh/docs/tasks/administer-cluster/out-of-resource.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/zh/docs/tasks/administer-cluster/out-of-resource.md b/content/zh/docs/tasks/administer-cluster/out-of-resource.md index ad792d4522..ba6a50cc7e 100644 --- a/content/zh/docs/tasks/administer-cluster/out-of-resource.md +++ b/content/zh/docs/tasks/administer-cluster/out-of-resource.md @@ -117,7 +117,7 @@ support in favor of eviction in response to disk pressure. `memory.available` 的值从 cgroupfs 获取,而不是通过类似 `free -m` 的工具。这很重要,因为 `free -m` 不能在容器中工作,并且如果用户使用了 [可分配节点](/docs/tasks/administer-cluster/reserve-compute-resources/#node-allocatable)特性,资源不足的判定将同时在本地 cgroup 层次结构的终端用户 pod 部分和根节点做出。这个 [脚本](/docs/tasks/administer-cluster/out-of-resource/memory-available.sh)复现了与 `kubelet` 计算 `memory.available` 相同的步骤。`kubelet`将`inactive_file`(意即活动 LRU 列表上基于文件后端的内存字节数)从计算中排除,因为它假设内存在出现压力时将被回收。 -`kub`elet` 只支持两种文件系统分区。 +`kubelet` 只支持两种文件系统分区。 1. `nodefs` 文件系统,kubelet 将其用于卷和守护程序日志等。 2. `imagefs` 文件系统,容器运行时用于保存镜像和容器可写层。 From 207c65404292e913f3146b01a2f139e57f468977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20L=C3=A9one?= Date: Sat, 15 Feb 2020 01:33:27 +0100 Subject: [PATCH 028/111] Add a theme-color (#18976) --- layouts/partials/head.html | 1 + 1 file changed, 1 insertion(+) diff --git a/layouts/partials/head.html b/layouts/partials/head.html index da38d8550e..e710c60af7 100644 --- a/layouts/partials/head.html +++ b/layouts/partials/head.html @@ -12,6 +12,7 @@ {{ if .Title }}{{ .Title }} - {{ end }}{{ site.Title }} + {{ partial "css.html" . }} From 3f6dfb1ee394ee60400de239eff615bef536be3a Mon Sep 17 00:00:00 2001 From: June Yi Date: Sat, 15 Feb 2020 10:59:27 +0900 Subject: [PATCH 029/111] Fourth Korean L10n Work For Release 1.17 (#19127) * translate assign-pod-node.md (#18955) * correct the misspelling (#19063) * Update to Outdated files in dev-1.17-ko.4 branch. (#19002) Co-Authored-By: KimMJ Co-Authored-By: forybm Co-Authored-By: Yuk, Yongsu Co-authored-by: KimMJ Co-authored-by: forybm Co-authored-by: Yuk, Yongsu --- .../concepts/architecture/cloud-controller.md | 2 + .../concepts/configuration/assign-pod-node.md | 399 ++++++++++++++++++ content/ko/docs/concepts/containers/images.md | 27 +- .../docs/concepts/containers/runtime-class.md | 13 +- .../ko/docs/concepts/overview/components.md | 11 +- .../docs/concepts/overview/kubernetes-api.md | 2 +- .../connect-applications-service.md | 2 +- .../services-networking/endpoint-slices.md | 119 +++++- .../ingress-controllers.md | 1 + .../concepts/services-networking/service.md | 27 +- .../workloads/controllers/replicaset.md | 8 +- .../workloads/pods/ephemeral-containers.md | 3 +- .../concepts/workloads/pods/pod-lifecycle.md | 2 +- .../docs/contribute/style/write-new-topic.md | 5 +- content/ko/docs/reference/glossary/cluster.md | 6 +- .../reference/glossary/container-runtime.md | 8 +- .../glossary/kube-controller-manager.md | 2 +- .../docs/reference/glossary/kube-scheduler.md | 4 +- .../docs/reference/glossary/pod-lifecycle.md | 6 +- .../reference/issues-security/security.md | 2 +- .../ko/docs/reference/kubectl/cheatsheet.md | 3 + content/ko/docs/setup/_index.md | 2 +- .../setup/best-practices/node-conformance.md | 2 +- .../setup/learning-environment/minikube.md | 9 +- .../container-runtimes.md | 18 +- .../production-environment/tools/kops.md | 106 +++-- .../cilium-network-policy.md | 44 +- .../resource-metrics-pipeline.md | 10 + .../declarative-config.md | 4 +- .../imperative-config.md | 4 +- .../horizontal-pod-autoscale-walkthrough.md | 2 +- .../horizontal-pod-autoscale.md | 203 ++++++++- content/ko/docs/tutorials/hello-minikube.md | 19 +- .../create-cluster/cluster-intro.html | 2 +- .../expose/expose-intro.html | 2 +- .../mysql-wordpress-persistent-volume.md | 14 +- content/ko/examples/minikube/Dockerfile | 2 +- content/ko/examples/pods/pod-nginx.yaml | 13 + .../examples/pods/pod-with-node-affinity.yaml | 26 ++ .../examples/pods/pod-with-pod-affinity.yaml | 29 ++ content/ko/includes/task-tutorial-prereqs.md | 6 +- 41 files changed, 967 insertions(+), 202 deletions(-) create mode 100644 content/ko/docs/concepts/configuration/assign-pod-node.md create mode 100644 content/ko/examples/pods/pod-nginx.yaml create mode 100644 content/ko/examples/pods/pod-with-node-affinity.yaml create mode 100644 content/ko/examples/pods/pod-with-pod-affinity.yaml diff --git a/content/ko/docs/concepts/architecture/cloud-controller.md b/content/ko/docs/concepts/architecture/cloud-controller.md index e21ff73c49..5c872bf06a 100644 --- a/content/ko/docs/concepts/architecture/cloud-controller.md +++ b/content/ko/docs/concepts/architecture/cloud-controller.md @@ -223,11 +223,13 @@ rules: 다음은 클라우드 제공사업자들이 구현한 CCM들이다. +* [Alibaba Cloud](https://github.com/kubernetes/cloud-provider-alibaba-cloud) * [AWS](https://github.com/kubernetes/cloud-provider-aws) * [Azure](https://github.com/kubernetes/cloud-provider-azure) * [BaiduCloud](https://github.com/baidu/cloud-provider-baiducloud) * [DigitalOcean](https://github.com/digitalocean/digitalocean-cloud-controller-manager) * [GCP](https://github.com/kubernetes/cloud-provider-gcp) +* [Hetzner](https://github.com/hetznercloud/hcloud-cloud-controller-manager) * [Linode](https://github.com/linode/linode-cloud-controller-manager) * [OpenStack](https://github.com/kubernetes/cloud-provider-openstack) * [Oracle](https://github.com/oracle/oci-cloud-controller-manager) diff --git a/content/ko/docs/concepts/configuration/assign-pod-node.md b/content/ko/docs/concepts/configuration/assign-pod-node.md new file mode 100644 index 0000000000..1c818457cb --- /dev/null +++ b/content/ko/docs/concepts/configuration/assign-pod-node.md @@ -0,0 +1,399 @@ +--- +title: 노드에 파드 할당하기 +content_template: templates/concept +weight: 30 +--- + + +{{% capture overview %}} + +{{< glossary_tooltip text="파드" term_id="pod" >}}를 특정한 {{< glossary_tooltip text="노드(들)" term_id="node" >}}에서만 동작하도록 하거나, +특정 노드들을 선호하도록 제한할 수 있다. +이를 수행하는 방법에는 여러 가지가 있으며, 권장되는 접근 방식은 모두 +[레이블 셀렉터](/ko/docs/concepts/overview/working-with-objects/labels/)를 사용하여 선택한다. +보통 스케줄러가 자동으로 합리적인 배치(예: 노드들에 걸쳐 파드를 분배하거나, +자원이 부족한 노드에 파드를 배치하지 않는 등)를 수행하기에 이런 제약 조건은 필요하지 않지만 +간혹 파드가 배치되는 노드에 대해 더 많은 제어를 원할 수 있는 상황이 있다. +예를 들어 SSD가 장착된 머신에 파드가 연결되도록 하거나 또는 동일한 가용성 영역(availability zone)에서 +많은 것을 통신하는 두 개의 서로 다른 서비스의 파드를 같이 배치할 수 있다. + +{{% /capture %}} + +{{% capture body %}} + +## 노드 셀렉터(nodeSelector) + +`nodeSelector` 는 가장 간단하고 권장되는 노드 선택 제약 조건의 형태이다. +`nodeSelector` 는 PodSpec의 필드이다. 이는 키-값 쌍의 매핑으로 지정한다. 파드가 노드에서 동작할 수 있으려면, +노드는 키-값의 쌍으로 표시되는 레이블을 각자 가지고 있어야 한다(이는 추가 레이블을 가지고 있을 수 있다). +일반적으로 하나의 키-값 쌍이 사용된다. + +`nodeSelector` 를 어떻게 사용하는지 예시를 통해 알아보도록 하자. + +### 0 단계: 사전 준비 + +이 예시는 쿠버네티스 파드에 대한 기본적인 이해를 하고 있고 [쿠버네티스 클러스터가 설정](/ko/docs/setup/)되어 있다고 가정한다. + +### 1 단계: 노드에 레이블 붙이기 + +`kubectl get nodes` 를 실행해서 클러스터 노드 이름을 가져온다. 이 중에 레이블을 추가하기 원하는 것 하나를 선택한 다음에 `kubectl label nodes <노드 이름> <레이블 키>=<레이블 값>` 을 실행해서 선택한 노드에 레이블을 추가한다. 예를 들어 노드의 이름이 'kubernetes-foo-node-1.c.a-robinson.internal' 이고, 원하는 레이블이 'disktype=ssd' 라면, `kubectl label nodes kubernetes-foo-node-1.c.a-robinson.internal disktype=ssd` 를 실행한다. + +`kubectl get nodes --show-labels` 를 다시 실행해서 노드가 현재 가진 레이블을 확인하여, 이 작업을 검증할 수 있다. 또한 `kubectl describe node "노드 이름"` 을 사용해서 노드에 주어진 레이블의 전체 목록을 확인할 수 있다. + +### 2 단계: 파드 설정에 nodeSelector 필드 추가하기 + +실행하고자 하는 파드의 설정 파일을 가져오고, 이처럼 nodeSelector 섹션을 추가한다. 예를 들어 이것이 파드 설정이라면, + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: nginx + labels: + env: test +spec: + containers: + - name: nginx + image: nginx +``` + +이 다음에 nodeSelector 를 다음과 같이 추가한다. + +{{< codenew file="pods/pod-nginx.yaml" >}} + +그런 다음에 `kubectl apply -f https://k8s.io/examples/pods/pod-nginx.yaml` 을 +실행하면, 레이블이 붙여진 노드에 파드가 스케줄 된다. +`kubectl get pods -o wide` 를 실행해서 파드가 할당된 +"NODE" 를 보면 작동하는지 검증할 수 있다. + +## 넘어가기 전에: 내장 노드 레이블들 {#built-in-node-labels} + +[붙인](#1-단계-노드에-레이블-붙이기) 레이블뿐만 아니라, 노드에는 +표준 레이블 셋이 미리 채워져 있다. 이 레이블들은 다음과 같다. + +* [`kubernetes.io/hostname`](/docs/reference/kubernetes-api/labels-annotations-taints/#kubernetes-io-hostname) +* [`failure-domain.beta.kubernetes.io/zone`](/docs/reference/kubernetes-api/labels-annotations-taints/#failure-domainbetakubernetesiozone) +* [`failure-domain.beta.kubernetes.io/region`](/docs/reference/kubernetes-api/labels-annotations-taints/#failure-domainbetakubernetesioregion) +* [`topology.kubernetes.io/zone`](/docs/reference/kubernetes-api/labels-annotations-taints/#topologykubernetesiozone) +* [`topology.kubernetes.io/region`](/docs/reference/kubernetes-api/labels-annotations-taints/#topologykubernetesiozone) +* [`beta.kubernetes.io/instance-type`](/docs/reference/kubernetes-api/labels-annotations-taints/#beta-kubernetes-io-instance-type) +* [`node.kubernetes.io/instance-type`](/docs/reference/kubernetes-api/labels-annotations-taints/#nodekubernetesioinstance-type) +* [`kubernetes.io/os`](/docs/reference/kubernetes-api/labels-annotations-taints/#kubernetes-io-os) +* [`kubernetes.io/arch`](/docs/reference/kubernetes-api/labels-annotations-taints/#kubernetes-io-arch) + +{{< note >}} +이 레이블들의 값은 클라우드 공급자에 따라 다르고 신뢰성이 보장되지 않는다. +예를 들어 `kubernetes.io/hostname` 은 어떤 환경에서는 노드 이름과 같지만, +다른 환경에서는 다른 값일 수 있다. +{{< /note >}} + +## 노드 격리(isolation)/제한(restriction) + +노드 오브젝트에 레이블을 추가하면 파드가 특정 노드 또는 노드 그룹을 목표 대상으로 할 수 있게 된다. +이는 특정 파드가 어떤 격리, 보안, 또는 규제 속성이 있는 노드에서만 실행되도록 사용할 수 있다. +이 목적으로 레이블을 사용하는 경우, 노드에서 kubelet 프로세스로 수정할 수 없는 레이블 키를 선택하는 것을 권장한다. +이렇게 하면 손상된 노드가 해당 kubelet 자격 증명을 사용해서 해당 레이블을 자체 노드 오브젝트에 설정하고, +스케줄러가 손상된 노드로 워크로드를 스케줄 하는 것을 방지할 수 있다. + +`NodeRestriction` 어드미션 플러그인은 kubelet이 `node-restriction.kubernetes.io/` 접두사로 레이블을 설정 또는 수정하지 못하게 한다. +노드 격리에 해당 레이블 접두사를 사용하려면 다음과 같이 한다. + +1. [노드 권한부여자](/docs/reference/access-authn-authz/node/)를 사용하고 있고, [NodeRestriction 어드미션 플러그인](/docs/reference/access-authn-authz/admission-controllers/#noderestriction)을 _활성화_ 해야 한다. +2. 노드 오브젝트의 `node-restriction.kubernetes.io/` 접두사 아래에 레이블을 추가하고, 해당 레이블을 노드 셀렉터에서 사용한다. +예를 들어, `example.com.node-restriction.kubernetes.io/fips=true` 또는 `example.com.node-restriction.kubernetes.io/pci-dss=true` 이다. + +## 어피니티(affinity)와 안티-어피니티(anti-affinity) + +`nodeSelector` 는 파드를 특정 레이블이 있는 노드로 제한하는 매우 간단한 방법을 제공한다. +어피니티/안티-어피니티 기능은 표현할 수 있는 제약 종류를 크게 확장한다. 주요 개선 사항은 다음과 같다. + +1. 언어가 보다 표현적이다("AND 또는 정확한 일치" 만이 아니다). +2. 규칙이 엄격한 요구 사항이 아니라 "유연한(soft)"/"선호(preference)" 규칙을 나타낼 수 있기에 스케줄러가 규칙을 만족할 수 없더라도, + 파드가 계속 스케줄 되도록 한다. +3. 노드 자체에 레이블을 붙이기보다는 노드(또는 다른 토폴로지 도메인)에서 실행 중인 다른 파드의 레이블을 제한할 수 있다. + 이를 통해 어떤 파드가 함께 위치할 수 있는지와 없는지에 대한 규칙을 적용할 수 있다. + +어피니티 기능은 "노드 어피니티" 와 "파드 간 어피니티/안티-어피니티" 두 종류의 어피니티로 구성된다. +노드 어피니티는 기존 `nodeSelector` 와 비슷하지만(그러나 위에서 나열된 첫째와 두 번째 이점이 있다.), +파드 간 어피니티/안티-어피니티는 위에서 나열된 세번째 항목에 설명된 대로 +노드 레이블이 아닌 파드 레이블에 대해 제한되고 위에서 나열된 첫 번째와 두 번째 속성을 가진다. + +### 노드 어피니티 + +노드 어피니티는 개념적으로 `nodeSelector` 와 비슷하다 -- 이는 노드의 레이블을 기반으로 파드를 +스케줄할 수 있는 노드를 제한할 수 있다. + +여기에 현재 `requiredDuringSchedulingIgnoredDuringExecution` 와 `preferredDuringSchedulingIgnoredDuringExecution` 로 부르는 +두 가지 종류의 노드 어피니티가 있다. 전자는 파드가 노드에 스케줄 되도록 *반드시* +규칙을 만족해야 하는 것(`nodeSelector` 와 같으나 보다 표현적인 구문을 사용해서)을 지정하고, +후자는 스케줄러가 시도하려고는 하지만, 보증하지 않는 *선호(preferences)* 를 지정한다는 점에서 +이를 각각 "엄격함(hard)" 과 "유연함(soft)" 으로 생각할 수 있다. +이름의 "IgnoredDuringExecution" 부분은 `nodeSelector` 작동 방식과 유사하게 노드의 +레이블이 런타임 중에 변경되어 파드의 어피니티 규칙이 더 이상 충족되지 않으면 파드가 여전히 그 노드에서 +동작한다는 의미이다. 향후에는 파드의 노드 어피니티 요구 사항을 충족하지 않는 노드에서 파드를 제거한다는 +점을 제외하고는 `preferredDuringSchedulingIgnoredDuringExecution` 와 같은 `requiredDuringSchedulingIgnoredDuringExecution` 를 제공할 계획이다. + +따라서 `requiredDuringSchedulingIgnoredDuringExecution` 의 예로는 "인텔 CPU가 있는 노드에서만 파드 실행"이 +될 수 있고, `preferredDuringSchedulingIgnoredDuringExecution` 의 예로는 "장애 조치 영역 XYZ에 파드 집합을 실행하려고 +하지만, 불가능하다면 다른 곳에서 일부를 실행하도록 허용"이 있을 것이다. + +노드 어피니티는 PodSpec의 `affinity` 필드의 `nodeAffinity` 필드에서 지정된다. + +여기에 노드 어피니티를 사용하는 파드 예시가 있다. + +{{< codenew file="pods/pod-with-node-affinity.yaml" >}} + +이 노드 어피니티 규칙은 키가 `kubernetes.io/e2e-az-name` 이고 값이 `e2e-az1` 또는 `e2e-az2` 인 +레이블이 있는 노드에만 파드를 배치할 수 있다고 말한다. 또한, 이 기준을 충족하는 노드들 +중에서 키가 `another-node-label-key` 이고 값이 `another-node-label-value` 인 레이블이 있는 노드를 +선호하도록 한다. + +예시에서 연산자 `In` 이 사용되고 있는 것을 볼 수 있다. 새로운 노드 어피니티 구문은 다음의 연산자들을 지원한다. `In`, `NotIn`, `Exists`, `DoesNotExist`, `Gt`, `Lt`. +`NotIn` 과 `DoesNotExist` 를 사용해서 안티-어피니티를 수행하거나, +특정 노드에서 파드를 쫓아내는 [노드 테인트(taint)](/docs/concepts/configuration/taint-and-toleration/)를 설정할 수 있다. + +`nodeSelector` 와 `nodeAffinity` 를 모두 지정한다면 파드가 후보 노드에 스케줄 되기 위해서는 +*둘 다* 반드시 만족해야 한다. + +`nodeAffinity` 유형과 연관된 `nodeSelectorTerms` 를 지정하면, 파드를 `nodeSelectorTerms` 가 지정된 것 중 **한 가지**라도 만족하는 노드에 스케줄할 수 있다. + +`nodeSelectorTerms` 와 연관된 여러 `matchExpressions` 를 지정하면, 파드는 `matchExpressions` 를 **모두** 만족하는 노드에만 스케줄할 수 있다. + +파드가 스케줄 된 노드의 레이블을 지우거나 변경해도 파드는 제거되지 않는다. 다시 말해서 어피니티 선택은 파드를 스케줄링 하는 시점에만 작동한다. + +`preferredDuringSchedulingIgnoredDuringExecution` 의 `weight` 필드의 범위는 1-100이다. 모든 스케줄링 요구 사항 (리소스 요청, RequiredDuringScheduling 어피니티 표현식 등)을 만족하는 각 노드들에 대해 스케줄러는 이 필드의 요소들을 반복해서 합계를 계산하고 노드가 MatchExpressions 에 일치하는 경우 합계에 "가중치(weight)"를 추가한다. 이후에 이 점수는 노드에 대한 다른 우선순위 함수의 점수와 합쳐진다. 전체 점수가 가장 높은 노드를 가장 선호한다. + +### 파드간 어피니티와 안티-어피니티 + +파드간 어피니티와 안티-어피니티를 사용하면 노드의 레이블을 기반으로 하지 않고, *노드에서 이미 실행 중인 파드 레이블을 기반으로* +파드가 스케줄될 수 있는 노드를 제한할 수 있다. 규칙은 "X가 규칙 Y를 충족하는 하나 이상의 파드를 이미 실행중인 경우 +이 파드는 X에서 실행해야 한다(또는 안티-어피니티가 없는 경우에는 동작하면 안된다)"는 형태이다. Y는 +선택적으로 연관된 네임스페이스 목록을 가진 LabelSelector로 표현된다. 노드와는 다르게 파드는 네임스페이스이기에 +(그리고 따라서 파드의 레이블은 암암리에 네임스페이스이다) 파드 레이블위의 레이블 셀렉터는 반드시 +셀렉터가 적용될 네임스페이스를 지정해야만 한다. 개념적으로 X는 노드, 랙, +클라우드 공급자 영역, 클라우드 공급자 지역 등과 같은 토폴로지 도메인이다. 시스템이 이런 토폴로지 +도메인을 나타내는 데 사용하는 노드 레이블 키인 `topologyKey` 를 사용하여 이를 표현한다. +예: [넘어가기 전에: 빌트인 노드 레이블](#built-in-node-labels) 섹션 위에 나열된 레이블 키를 본다. + +{{< note >}} +파드간 어피니티와 안티-어피니티에는 상당한 양의 프로세싱이 필요하기에 +대규모 클러스터에서는 스케줄링 속도가 크게 느려질 수 있다. +수백 개의 노드를 넘어가는 클러스터에서 이를 사용하는 것은 추천하지 않는다. +{{< /note >}} + +{{< note >}} +파드 안티-어피니티에서는 노드에 일관된 레이블을 지정해야 한다. 즉, 클러스터의 모든 노드는 `topologyKey` 와 매칭되는 적절한 레이블을 가지고 있어야 한다. 일부 또는 모든 노드에 지정된 `topologyKey` 레이블이 없는 경우에는 의도하지 않은 동작이 발생할 수 있다. +{{< /note >}} + +노드 어피니티와 마찬가지로 현재 파드 어피니티와 안티-어피니티로 부르는 "엄격함" 대 "유연함"의 요구사항을 나타내는 `requiredDuringSchedulingIgnoredDuringExecution` 와 +`preferredDuringSchedulingIgnoredDuringExecution` 두 가지 종류가 있다. +앞의 노드 어피니티 섹션의 설명을 본다. +`requiredDuringSchedulingIgnoredDuringExecution` 어피니티의 예시는 +"서로 많은 통신을 하기 때문에 서비스 A와 서비스 B를 같은 영역에 함께 위치시키는 것"이고, +`preferredDuringSchedulingIgnoredDuringExecution` 안티-어피니티의 예시는 "서비스를 여러 영역에 걸쳐서 분배하는 것"이다 +(엄격한 요구사항은 영역보다 파드가 더 많을 수 있기 때문에 엄격한 요구사항은 의미가 없다). + +파드간 어피니티는 PodSpec에서 `affinity` 필드 중 `podAffinity` 필드로 지정한다. +그리고 파드간 안티-어피니티는 PodSpec에서 `affinity` 필드 중 `podAntiAffinity` 필드로 지정한다. + +#### 파드 어피니티를 사용하는 파드의 예시 + +{{< codenew file="pods/pod-with-pod-affinity.yaml" >}} + +이 파드의 어피니티는 하나의 파드 어피니티 규칙과 하나의 파드 안티-어피니티 규칙을 정의한다. +이 예시에서 `podAffinity` 는 `requiredDuringSchedulingIgnoredDuringExecution` 이고 `podAntiAffinity` 는 +`preferredDuringSchedulingIgnoredDuringExecution` 이다. 파드 어피니티 규칙에 의하면 키 "security" 와 값 +"S1"인 레이블이 있는 하나 이상의 이미 실행 중인 파드와 동일한 영역에 있는 경우에만 파드를 노드에 스케줄할 수 있다. +(보다 정확하게는, 클러스터에 키 "security"와 값 "S1"인 레이블을 가지고 있는 실행 중인 파드가 있는 키 +`failure-domain.beta.kubernetes.io/zone` 와 값 V인 노드가 최소 하나 이상 있고, 노드 N이 키 +`failure-domain.beta.kubernetes.io/zone` 와 일부 값이 V인 레이블을 가진다면 파드는 노드 N에서 실행할 수 있다.) +파드 안티-어피니티 규칙에 의하면 노드가 이미 키 "security"와 값 "S2"인 레이블을 가진 파드를 +실행하고 있는 파드는 노드에 스케줄되는 것을 선호하지 않는다. +(만약 `topologyKey` 가 `failure-domain.beta.kubernetes.io/zone` 라면 노드가 키 +"security"와 값 "S2"를 레이블로 가진 파드와 +동일한 영역에 있는 경우, 노드에 파드를 예약할 수 없음을 의미한다.) +[디자인 문서](https://git.k8s.io/community/contributors/design-proposals/scheduling/podaffinity.md)를 통해 +`requiredDuringSchedulingIgnoredDuringExecution` 와 `preferredDuringSchedulingIgnoredDuringExecution` 의 +파드 어피니티와 안티-어피니티에 대한 많은 예시를 맛볼 수 있다. + +파드 어피니티와 안티-어피니티의 적합한 연산자는 `In`, `NotIn`, `Exists`, `DoesNotExist` 이다. + +원칙적으로, `topologyKey` 는 적법한 어느 레이블-키도 될 수 있다. +하지만, 성능과 보안상의 이유로 topologyKey에는 몇 가지 제약조건이 있다. + +1. 어피니티와 `requiredDuringSchedulingIgnoredDuringExecution` 파드 안티-어피니티는 대해 +`topologyKey` 가 비어있는 것을 허용하지 않는다. +2. `requiredDuringSchedulingIgnoredDuringExecution` 파드 안티-어피니티에서 `topologyKey` 를 `kubernetes.io/hostname` 로 제한하기 위해 어드미션 컨트롤러 `LimitPodHardAntiAffinityTopology` 가 도입되었다. 사용자 지정 토폴로지를에 사용할 수 있도록 하려면, 어드미션 컨트롤러를 수정하거나 간단히 이를 비활성화 할 수 있다. +3. `preferredDuringSchedulingIgnoredDuringExecution` 파드 안티-어피니티의 경우 빈 `topologyKey` 는 "all topology"("all topology"는 현재 `kubernetes.io/hostname`, `failure-domain.beta.kubernetes.io/zone` 그리고 `failure-domain.beta.kubernetes.io/region` 의 조합으로 제한된다)로 해석한다. +4. 위의 경우를 제외하고, `topologyKey` 는 적법한 어느 레이블-키도 가능하다. + +`labelSelector` 와 `topologyKey` 외에도 `labelSelector` 와 일치해야 하는 네임스페이스 목록 `namespaces` 를 +선택적으로 지정할 수 있다(이것은 `labelSelector` 와 `topologyKey` 와 같은 수준의 정의이다). +생략되어있거나 비어있을 경우 어피니티/안티-어피니티 정의가 있는 파드의 네임스페이스가 기본 값이다. + +파드를 노드에 스케줄하려면 `requiredDuringSchedulingIgnoredDuringExecution` 어피니티와 안티-어피니티와 +연관된 `matchExpressions` 가 모두 충족되어야 한다. + +#### 더 실용적인 유스케이스 + +파드간 어피니티와 안티-어피니티는 레플리카셋, 스테이트풀셋, 디플로이먼트 등과 같은 +상위 레벨 모음과 함께 사용할 때 더욱 유용할 수 있다. 워크로드 집합이 동일한 노드와 같이 +동일하게 정의된 토폴로지와 같은 위치에 배치되도록 쉽게 구성할 수 있다. + +##### 항상 같은 노드에 위치시키기 + +세 개의 노드가 있는 클러스터에서 웹 애플리케이션에는 redis와 같은 인-메모리 캐시가 있다. 웹 서버가 가능한 캐시와 함께 위치하기를 원한다. + +다음은 세 개의 레플리카와 셀렉터 레이블이 `app=store` 가 있는 간단한 redis 디플로이먼트의 yaml 스니펫이다. 디플로이먼트에는 스케줄러가 단일 노드에서 레플리카를 함께 배치하지 않도록 `PodAntiAffinity` 가 구성되어 있다. + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: redis-cache +spec: + selector: + matchLabels: + app: store + replicas: 3 + template: + metadata: + labels: + app: store + spec: + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: app + operator: In + values: + - store + topologyKey: "kubernetes.io/hostname" + containers: + - name: redis-server + image: redis:3.2-alpine +``` + +아래 yaml 스니펫의 웹서버 디플로이먼트는 `podAntiAffinity` 와 `podAffinity` 설정을 가지고 있다. 이렇게 하면 스케줄러에 모든 레플리카는 셀렉터 레이블이 `app=store` 인 파드와 함께 위치해야 한다. 또한 각 웹 서버 레플리카가 단일 노드의 같은 위치에 있지 않도록 한다. + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: web-server +spec: + selector: + matchLabels: + app: web-store + replicas: 3 + template: + metadata: + labels: + app: web-store + spec: + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: app + operator: In + values: + - web-store + topologyKey: "kubernetes.io/hostname" + podAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: app + operator: In + values: + - store + topologyKey: "kubernetes.io/hostname" + containers: + - name: web-app + image: nginx:1.12-alpine +``` + +만약 위의 두 디플로이먼트를 생성하면 세 개의 노드가 있는 클러스터는 다음과 같아야 한다. + +| node-1 | node-2 | node-3 | +|:--------------------:|:-------------------:|:------------------:| +| *webserver-1* | *webserver-2* | *webserver-3* | +| *cache-1* | *cache-2* | *cache-3* | + +여기서 볼 수 있듯이 `web-server` 의 세 레플리카들이 기대했던 것처럼 자동으로 캐시와 함께 위치하게 된다. + +``` +kubectl get pods -o wide +``` +출력은 다음과 유사할 것이다. +``` +NAME READY STATUS RESTARTS AGE IP NODE +redis-cache-1450370735-6dzlj 1/1 Running 0 8m 10.192.4.2 kube-node-3 +redis-cache-1450370735-j2j96 1/1 Running 0 8m 10.192.2.2 kube-node-1 +redis-cache-1450370735-z73mh 1/1 Running 0 8m 10.192.3.1 kube-node-2 +web-server-1287567482-5d4dz 1/1 Running 0 7m 10.192.2.3 kube-node-1 +web-server-1287567482-6f7v5 1/1 Running 0 7m 10.192.4.3 kube-node-3 +web-server-1287567482-s330j 1/1 Running 0 7m 10.192.3.2 kube-node-2 +``` + +##### 절대 동일한 노드에 위치시키지 않게 하기 + +위의 예시에서 `topologyKey:"kubernetes.io/hostname"` 과 함께 `PodAntiAffinity` 규칙을 사용해서 +두 개의 인스터스가 동일한 호스트에 있지 않도록 redis 클러스터를 배포한다. +같은 기술을 사용해서 고 가용성을 위해 안티-어피니티로 구성된 스테이트풀셋의 예시는 +[ZooKeeper 튜토리얼](/docs/tutorials/stateful-application/zookeeper/#tolerating-node-failure)을 본다. + +## nodeName + +`nodeName` 은 가장 간단한 형태의 노트 선택 제약 조건이지만, +한계로 인해 일반적으로는 사용하지 않는다. +`nodeName` 은 PodSpec의 필드이다. 만약 비어있지 않으면, 스케줄러는 +파드를 무시하고 명명된 노드에서 실행 중인 kubelet이 +파드를 실행하려고 한다. 따라서 만약 PodSpec에 `nodeName` 가 +제공된 경우, 노드 선텍을 위해 위의 방법보다 우선한다. + +`nodeName` 을 사용해서 노드를 선택할 때의 몇 가지 제한은 다음과 같다. + +- 만약 명명된 노드가 없으면, 파드가 실행되지 않고 + 따라서 자동으로 삭제될 수 있다. +- 만약 명명된 노드에 파드를 수용할 수 있는 + 리소스가 없는 경우 파드가 실패하고, 그 이유는 다음과 같이 표시된다. + 예: OutOfmemory 또는 OutOfcpu. +- 클라우드 환경의 노드 이름은 항상 예측 가능하거나 + 안정적인 것은 아니다. + +여기에 `nodeName` 필드를 사용하는 파드 설정 파일 예시가 있다. + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx + nodeName: kube-01 +``` + +위 파드는 kube-01 노드에서 실행될 것이다. + +{{% /capture %}} + +{{% capture whatsnext %}} + +[테인트](/docs/concepts/configuration/taint-and-toleration/)는 노드가 특정 파드들을 *쫓아내게* 할 수 있다. + +[노드 어피니티](https://git.k8s.io/community/contributors/design-proposals/scheduling/nodeaffinity.md)와 +[파드간 어피니티/안티-어피니티](https://git.k8s.io/community/contributors/design-proposals/scheduling/podaffinity.md)에 대한 디자인 문서에는 +이러한 기능에 대한 추가 배경 정보가 있다. + +파드가 노드에 할당되면 kubelet은 파드를 실행하고 노드의 로컬 리소스를 할당한다. +[토폴로지 매니저](/docs/tasks/administer-cluster/topology-manager/)는 +노드 수준의 리소스 할당 결정에 참여할 수 있다. + +{{% /capture %}} diff --git a/content/ko/docs/concepts/containers/images.md b/content/ko/docs/concepts/containers/images.md index c0d4fe4b0b..3bc71c53c8 100644 --- a/content/ko/docs/concepts/containers/images.md +++ b/content/ko/docs/concepts/containers/images.md @@ -120,9 +120,9 @@ kubelet은 ECR 자격 증명을 가져오고 주기적으로 갱신할 것이다 - 위의 모든 요구 사항을 확인한다. - 워크스테이션에서 $REGION (예: `us-west-2`)의 자격 증명을 얻는다. 그 자격 증명을 사용하여 해당 호스트로 SSH를 하고 Docker를 수동으로 실행한다. 작동하는가? - kubelet이 `--cloud-provider=aws`로 실행 중인지 확인한다. -- kubelet 로그에서 (예: `journalctl -u kubelet`) 다음과 같은 로그 라인을 확인한다. - - `plugins.go:56] Registering credential provider: aws-ecr-key` - - `provider.go:91] Refreshing cache for provider: *aws_credentials.ecrProvider` +- kubelet 로그 수준을 최소 3 이상으로 늘리고 kubelet 로그에서 (예: `journalctl -u kubelet`) 다음과 같은 로그 라인을 확인한다. + - `aws_credentials.go:109] unable to get ECR credentials from cache, checking ECR API` + - `aws_credentials.go:116] Got ECR credentials from ECR API for .dkr.ecr..amazonaws.com` ### Azure 컨테이너 레지스트리(ACR) 사용 [Azure 컨테이너 레지스트리](https://azure.microsoft.com/en-us/services/container-registry/)를 사용하는 경우 @@ -202,7 +202,7 @@ Docker는 프라이빗 레지스트리를 위한 키를 `$HOME/.dockercfg` 또 프라이빗 이미지를 사용하는 파드를 생성하여 검증한다. 예를 들면 다음과 같다. -```yaml +```shell kubectl apply -f - <}} 런타임 핸들러는 containerd의 구성 파일인 `/etc/containerd/config.toml` 통해 설정한다. 유효한 핸들러는 runtimes 단락 아래에서 설정한다. @@ -129,10 +129,10 @@ CRI 런타임 설치에 대한 자세한 내용은 [CRI 설치](/docs/setup/prod 더 자세한 containerd의 구성 문서를 살펴본다. https://github.com/containerd/cri/blob/master/docs/config.md -#### [cri-o](https://cri-o.io/) +#### {{< glossary_tooltip term_id="cri-o" >}} -런타임 핸들러는 cri-o의 구성파일인 `/etc/crio/crio.conf`을 통해 설정한다. -[crio.runtime 테이블](https://github.com/kubernetes-sigs/cri-o/blob/master/docs/crio.conf.5.md#crioruntime-table) 아래에 +런타임 핸들러는 CRI-O의 구성파일인 `/etc/crio/crio.conf`을 통해 설정한다. +[crio.runtime 테이블](https://github.com/cri-o/cri-o/blob/master/docs/crio.conf.5.md#crioruntime-table) 아래에 유효한 핸들러를 설정한다. ``` @@ -140,8 +140,9 @@ https://github.com/containerd/cri/blob/master/docs/config.md runtime_path = "${PATH_TO_BINARY}" ``` -더 자세한 cri-o의 구성 문서를 살펴본다. -https://github.com/kubernetes-sigs/cri-o/blob/master/cmd/crio/config.go +더 자세한 것은 CRI-O의 [설정 문서][100]를 본다. + +[100]: https://raw.githubusercontent.com/cri-o/cri-o/9f11d1d/docs/crio.conf.5.md ### 스케줄 diff --git a/content/ko/docs/concepts/overview/components.md b/content/ko/docs/concepts/overview/components.md index 541e4f164c..dae6876343 100644 --- a/content/ko/docs/concepts/overview/components.md +++ b/content/ko/docs/concepts/overview/components.md @@ -9,7 +9,7 @@ card: {{% capture overview %}} 쿠버네티스를 배포하면 클러스터를 얻는다. -{{< glossary_definition term_id="cluster" length="all" prepend="클러스터는">}} +{{< glossary_definition term_id="cluster" length="all" prepend="쿠버네티스 클러스터는">}} 이 문서는 완전히 작동하는 쿠버네티스 클러스터를 갖기 위해 필요한 다양한 컴포넌트들에 대해 요약하고 정리한다. @@ -21,13 +21,12 @@ card: {{% /capture %}} {{% capture body %}} -## 마스터 컴포넌트 +## 컨트롤 플래인 컴포넌트 -마스터 컴포넌트는 클러스터의 컨트롤 플레인을 제공한다. 마스터 컴포넌트는 클러스터에 관한 전반적인 결정 -(예를 들어, 스케줄링)을 수행하고 클러스터 이벤트(예를 들어, 디플로이먼트의 `replicas` 필드가 요구조건을 충족되지 않을 경우 새로운 {{< glossary_tooltip text="파드" term_id="pod">}}를 구동시키는 것)를 감지하고 반응한다. +컨트롤 플래인 컴포넌트는 클러스터에 관한 전반적인 결정(예를 들어, 스케줄링)을 수행하고 클러스터 이벤트(예를 들어, 디플로이먼트의 `replicas` 필드에 대한 요구조건을 충족되지 않을 경우 새로운 {{< glossary_tooltip text="파드" term_id="pod">}}를 구동시키는 것)를 감지하고 반응한다. -마스터 컴포넌트는 클러스터 내 어떠한 머신에서든지 동작 될 수 있다. 그러나 -간결성을 위하여, 구성 스크립트는 보통 동일 머신 상에 모든 마스터 컴포넌트를 구동시키고, +컨트롤 플래인 컴포넌트는 클러스터 내 어떠한 머신에서든지 동작 될 수 있다. 그러나 +간결성을 위하여, 구성 스크립트는 보통 동일 머신 상에 모든 컨트롤 플래인 컴포넌트를 구동시키고, 사용자 컨테이너는 해당 머신 상에 동작시키지 않는다. 다중-마스터-VM 설치 예제를 보려면 [고가용성 클러스터 구성하기](/docs/admin/high-availability/)를 확인해본다. diff --git a/content/ko/docs/concepts/overview/kubernetes-api.md b/content/ko/docs/concepts/overview/kubernetes-api.md index e3d9981a3a..bc38340964 100644 --- a/content/ko/docs/concepts/overview/kubernetes-api.md +++ b/content/ko/docs/concepts/overview/kubernetes-api.md @@ -59,7 +59,7 @@ GET /swagger-2.0.0.pb-v1.gz | GET /openapi/v2 **Accept**: application/com.github 1.14 이전 버전에서 쿠버네티스 apiserver는 `/swaggerapi`에서 [Swagger v1.2](http://swagger.io/) 쿠버네티스 API 스펙을 검색하는데 사용할 수 있는 API도 제공한다. -이러한 엔드포인트는 사용 중단되었으며, 쿠버네티스 1.14에서 제거될 예정이다. +이러한 엔드포인트는 사용 중단되었으며, 쿠버네티스 1.14에서 제거되었다. ## API 버전 규칙 diff --git a/content/ko/docs/concepts/services-networking/connect-applications-service.md b/content/ko/docs/concepts/services-networking/connect-applications-service.md index fce55dbf8e..361660a119 100644 --- a/content/ko/docs/concepts/services-networking/connect-applications-service.md +++ b/content/ko/docs/concepts/services-networking/connect-applications-service.md @@ -13,7 +13,7 @@ weight: 30 기본적으로 도커는 호스트-프라이빗 네트워킹을 사용하기에 컨테이너는 동일한 머신에 있는 경우에만 다른 컨테이너와 통신 할 수 있다. 도커 컨테이너가 노드를 통해 통신하려면 머신 포트에 IP 주소가 할당되어야 컨테이너에 전달되거나 프록시된다. 이것은 컨테이너가 사용하는 포트를 매우 신중하게 조정하거나 포트를 동적으로 할당해야 한다는 의미이다. -여러 개발자에 걸쳐있는 포트를 조정하는 것은 규모면에서 매우 어려우며, 사용자가 제어할 수 없는 클러스터 수준의 문제에 노출된다. 쿠버네티스는 파드가 배치된 호스트와는 무관하게 다른 파드와 통신할 수 있다고 가정한다. 모든 파드에게 자체 클러스터-프라이빗-IP 주소를 제공하기 때문에 파드간에 명시적으로 링크를 만들거나 컨테이너 포트를 호스트 포트에 매핑 할 필요가 없다. 이것은 파드 내의 컨테이너는 모두 로컬호스트에서 서로의 포트에 도달할 수 있으며 클러스터의 모든 파드는 NAT 없이 서로를 볼 수 있다는 의미이다. 이 문서의 나머지 부분에서는 이러한 네트워킹 모델에서 신뢰할 수 있는 서비스를 실행하는 방법에 대해 자세히 설명할 것이다. +컨테이너를 제공하는 여러 개발자 또는 팀에서 포트를 조정하는 것은 규모면에서 매우 어려우며, 사용자가 제어할 수 없는 클러스터 수준의 문제에 노출된다. 쿠버네티스는 파드가 배치된 호스트와는 무관하게 다른 파드와 통신할 수 있다고 가정한다. 쿠버네티스는 모든 파드에게 자체 클러스터-프라이빗 IP 주소를 제공하기 때문에 파드간에 명시적으로 링크를 만들거나 컨테이너 포트를 호스트 포트에 매핑 할 필요가 없다. 이것은 파드 내의 컨테이너는 모두 로컬호스트에서 서로의 포트에 도달할 수 있으며 클러스터의 모든 파드는 NAT 없이 서로를 볼 수 있다는 의미이다. 이 문서의 나머지 부분에서는 이러한 네트워킹 모델에서 신뢰할 수 있는 서비스를 실행하는 방법에 대해 자세히 설명할 것이다. 이 가이드는 간단한 nginx 서버를 사용해서 개념증명을 보여준다. 동일한 원칙이 보다 완전한 [Jenkins CI 애플리케이션](https://kubernetes.io/blog/2015/07/strong-simple-ssl-for-kubernetes)에서 구현된다. diff --git a/content/ko/docs/concepts/services-networking/endpoint-slices.md b/content/ko/docs/concepts/services-networking/endpoint-slices.md index b8f154c152..f40ff87993 100644 --- a/content/ko/docs/concepts/services-networking/endpoint-slices.md +++ b/content/ko/docs/concepts/services-networking/endpoint-slices.md @@ -1,7 +1,7 @@ --- -title: 엔드포인트 슬라이스 +title: 엔드포인트슬라이스 feature: - title: 엔드포인트 슬라이스 + title: 엔드포인트슬라이스 description: > 쿠버네티스 클러스터에서 확장 가능한 네트워크 엔드포인트 추적. @@ -14,7 +14,7 @@ weight: 10 {{< feature-state for_k8s_version="v1.17" state="beta" >}} -_엔드포인트 슬라이스_ 는 쿠버네티스 클러스터 내의 네트워크 엔드포인트를 +_엔드포인트슬라이스_ 는 쿠버네티스 클러스터 내의 네트워크 엔드포인트를 추적하는 간단한 방법을 제공한다. 이것은 엔드포인트를 더 확장하고, 확장 가능한 대안을 제안한다. @@ -22,13 +22,14 @@ _엔드포인트 슬라이스_ 는 쿠버네티스 클러스터 내의 네트워 {{% capture body %}} -## 엔드포인트 슬라이스 리소스 {#endpointslice-resource} +## 엔드포인트슬라이스 리소스 {#endpointslice-resource} 쿠버네티스에서 EndpointSlice는 일련의 네트워크 엔드 포인트에 대한 -참조를 포함한다. 쿠버네티스 서비스에 셀렉터가 지정되면 EndpointSlice -컨트롤러는 자동으로 엔드포인트 슬라이스를 생성한다. 이 엔드포인트 슬라이스는 -서비스 셀렉터와 매치되는 모든 파드들을 포함하고 참조한다. 엔드포인트 -슬라이스는 고유한 서비스와 포트 조합을 통해 네트워크 엔드포인트를 그룹화 한다. +참조를 포함한다. 쿠버네티스 서비스에 {{< glossary_tooltip text="셀렉터" +term_id="selector" >}} 가 지정되면 EndpointSlice +컨트롤러는 자동으로 엔드포인트슬라이스를 생성한다. 이 엔드포인트슬라이스는 +서비스 셀렉터와 매치되는 모든 파드들을 포함하고 참조한다. 엔드포인트슬라이스는 +고유한 서비스와 포트 조합을 통해 네트워크 엔드포인트를 그룹화 한다. 예를 들어, 여기에 `example` 쿠버네티스 서비스를 위한 EndpointSlice 리소스 샘플이 있다. @@ -47,7 +48,7 @@ ports: port: 80 endpoints: - addresses: - - "10.1.2.3" + - "10.1.2.3" conditions: ready: true hostname: pod-1 @@ -56,15 +57,15 @@ endpoints: topology.kubernetes.io/zone: us-west2-a ``` -기본적으로, EndpointSlice 컨트롤러가 관리하는 엔드포인트 슬라이스에는 -각각 100개 이하의 엔드포인트를 가지고 있다. 이 스케일 아래에서 엔드포인트 슬라이스는 +기본적으로, EndpointSlice 컨트롤러가 관리하는 엔드포인트슬라이스에는 +각각 100개 이하의 엔드포인트를 가지고 있다. 이 스케일 아래에서 엔드포인트슬라이스는 엔드포인트 및 서비스와 1:1로 매핑해야하며, 유사한 성능을 가져야 한다. -엔드포인트 슬라이스는 내부 트래픽을 라우트하는 방법에 대해 kube-proxy에 +엔드포인트슬라이스는 내부 트래픽을 라우트하는 방법에 대해 kube-proxy에 신뢰할 수 있는 소스로 역할을 할 수 있다. 이를 활성화 하면, 많은 수의 엔드포인트를 가지는 서비스에 대해 성능 향상을 제공해야 한다. -## 주소 유형 +### 주소 유형 EndpointSlice는 다음 주소 유형을 지원한다. @@ -72,6 +73,94 @@ EndpointSlice는 다음 주소 유형을 지원한다. * IPv6 * FQDN (Fully Qualified Domain Name) +### 토폴로지 + +엔드포인트슬라이스 내 각 엔드포인트는 연관된 토폴로지 정보를 포함할 수 있다. +이는 해당 노드, 영역 그리고 지역에 대한 정보가 포함된 +엔드포인트가 있는 위치를 나타나는데 사용 한다. 값을 사용할 수 있으면 +다음의 토폴로지 레이블이 엔드포인트슬라이스 컨트롤러에 의해 설정된다. + +* `kubernetes.io/hostname` - 이 엔드포인트가 있는 노드의 이름. +* `topology.kubernetes.io/zone` - 이 엔드포인트가 있는 영역의 이름. +* `topology.kubernetes.io/region` - 이 엔드포인트가 있는 지역의 이름. + +이런 레이블 값은 슬라이스의 각 엔드포인트와 연관된 리소스에서 +파생된다. 호스트 이름 레이블은 해당 파드의 +NodeName 필드 값을 나타낸다. 영역 및 지역 레이블은 해당 +노드에서 이름이 같은 값을 나타낸다. + +### 관리 + +기본적으로 엔드포인트슬라이스는 엔드포인트슬라이스 컨트롤러에의해 +생성되고 관리된다. 서비스 메시 구현과 같은 다른 엔드포인트슬라이스 +유스 케이스는 다른 엔터티나 컨트롤러가 추가 엔드포인트슬라이스 +집합을 관리할 수 있게 할 수 있다. 여러 엔티티가 서로 간섭하지 않고 +엔드포인트슬라이스를 관리할 수 있도록 엔드포인트슬라이스를 관리하는 +엔티티를 나타내는데 `endpointslice.kubernetes.io/managed-by` 레이블이 사용된다. +엔드포인트슬라이스 컨트롤러는 관리하는 모든 엔드포인트 +슬라이스에 레이블의 값으로 `endpointslice-controller.k8s.io` 를 설정한다. +엔드포인트슬라이스를 관리하는 다른 엔티티도 이 레이블에 +고유한 값을 설정해야 한다. + +### 소유권 + +대부분의 유스 케이스에서 엔드포인트를 추적하는 서비스가 엔드포인트슬라이스를 +소유한다. 이는 각 엔드포인트슬라이스의 참조와 서비스에 속하는 모든 +엔드포인트슬라이스를 간단하게 조회할 수 있는 `kubernetes.io/service-name` +레이블로 표시된다. + +## 엔드포인트슬라이스 컨트롤러 + +엔드포인트슬라이스 컨트롤러는 해당 엔드포인트슬라이스가 최신 상태인지 +확인하기 위해 서비스와 파드를 감시한다. 컨트롤러가 셀렉터로 지정한 모든 +서비스에 대해 엔드포인트슬라이스를 관리한다. 이는 서비스 셀렉터와 +일치하는 파드의 IP를 나타내게 된다. + +### 엔드포인트슬라이스의 크기 + +기본적으로 엔드포인트슬라이스는 각각 100개의 엔드포인트 크기로 제한된다. +최대 1000개까지 `--max-endpoints-per-slice` {{< glossary_tooltip +text="kube-controller-manager" term_id="kube-controller-manager" >}} 플래그를 +사용해서 구성할 수 있다. + +### 엔드포인트슬라이스의 배포 + +각 엔드포인트슬라이스에는 리소스 내에 모든 엔드포인트가 적용되는 +포트 집합이 있다. 서비스에 알려진 포트를 사용하는 경우 파드는 +동일하게 알려진 포트에 대해 다른 대상 포트 번호로 끝날 수 있으며 다른 +엔드포인트슬라이스가 필요하다. 이는 하위 집합이 엔드포인트와 그룹화하는 +방식의 논리와 유사하다. + +컨트롤러는 엔드포인트슬라이스를 최대한 채우려고 노력하지만, +적극적으로 재조정하지는 않는다. 컨트롤러의 동작은 매우 직관적이다. + +1. 기존 엔드포인트슬라이스에 대해 반복적으로, 더 이상 필요하지 않는 엔드포인트를 + 제거하고 변경에 의해 일치하는 엔드포인트를 업데이트 한다. +2. 첫 번째 단계에서 수정된 엔드포인트슬라이스를 반복해서 + 필요한 새 엔드포인트로 채운다. +3. 추가할 새 엔드포인트가 여전히 남아있으면, 이전에 변경되지 않은 + 슬라이스에 엔드포인트를 맞추거나 새로운 것을 생성한다. + +중요한 것은, 세 번째 단계는 엔드포인트슬라이스를 완벽하게 전부 배포하는 것보다 +엔드포인트슬라이스 업데이트 제한을 우선시한다. 예를 들어, 추가할 새 엔드포인트가 +10개이고 각각 5개의 공간을 사용할 수 있는 엔드포인트 공간이 있는 2개의 +엔드포인트슬라이스가 있는 경우, 이 방법은 기존 엔드포인트슬라이스 +2개를 채우는 대신에 새 엔드포인트슬라이스를 생성한다. 다른 말로, 단일 +엔드포인트슬라이스를 생성하는 것이 여러 엔드포인트슬라이스를 업데이트하는 것 보다 더 선호된다. + +각 노드에서 kube-proxy를 실행하고 엔드포인트슬라이스를 관찰하면, +엔드포인트슬라이스에 대한 모든 변경 사항이 클러스터의 모든 노드로 전송되기 +때문에 상대적으로 비용이 많이 소요된다. 이 방법은 여러 엔드포인트슬라이스가 +가득 차지 않은 결과가 발생할지라도, 모든 노드에 전송해야 하는 +변경 횟수를 의도적으로 제한하기 위한 것이다. + +실제로는, 이러한 이상적이지 않은 분배는 드물 것이다. 엔드포인트슬라이스 +컨트롤러에서 처리하는 대부분의 변경 내용은 기존 엔드포인트슬라이스에 +적합할 정도로 적고, 그렇지 않은 경우 새 엔드포인트슬라이스가 +필요할 수 있다. 디플로이먼트의 롤링 업데이트도 모든 파드와 해당 +교체되는 엔드포인트에 대해서 엔드포인트슬라이스를 +자연스럽게 재포장한다. + ## 사용동기 엔드포인트 API는 쿠버네티스에서 네트워크 엔드포인트를 추적하는 @@ -84,14 +173,14 @@ EndpointSlice는 다음 주소 유형을 지원한다. 리소스에 저장되기 때문에 엔드포인트 리소스가 상당히 커질 수 있다. 이것은 쿠버네티스 구성요소 (특히 마스터 컨트롤 플레인)의 성능에 영향을 미쳤고 엔드포인트가 변경될 때 상당한 양의 네트워크 트래픽과 처리를 초래했다. -엔드포인트 슬라이스는 이러한 문제를 완화하고 토폴로지 라우팅과 +엔드포인트슬라이스는 이러한 문제를 완화하고 토폴로지 라우팅과 같은 추가 기능을 위한 확장 가능한 플랫폼을 제공한다. {{% /capture %}} {{% capture whatsnext %}} -* [엔드포인트 슬라이스 활성화하기](/docs/tasks/administer-cluster/enabling-endpointslices) +* [엔드포인트슬라이스 활성화하기](/docs/tasks/administer-cluster/enabling-endpointslices) * [애플리케이션을 서비스와 함께 연결하기](/ko/docs/concepts/services-networking/connect-applications-service/) 를 읽는다. {{% /capture %}} diff --git a/content/ko/docs/concepts/services-networking/ingress-controllers.md b/content/ko/docs/concepts/services-networking/ingress-controllers.md index cd8337ef0a..92a2387f5d 100644 --- a/content/ko/docs/concepts/services-networking/ingress-controllers.md +++ b/content/ko/docs/concepts/services-networking/ingress-controllers.md @@ -21,6 +21,7 @@ kube-controller-manager 바이너리의 일부로 실행되는 컨트롤러의 ## 추가 컨트롤러 +* [AKS Application Gateway Ingress Controller](https://github.com/Azure/application-gateway-kubernetes-ingress) is an ingress controller that enables ingress to [AKS clusters](https://docs.microsoft.com/azure/aks/kubernetes-walkthrough-portal) using the [Azure Application Gateway](https://docs.microsoft.com/azure/application-gateway/overview). * [Ambassador](https://www.getambassador.io/) API 게이트웨이는 [Datawire](https://www.datawire.io/)의 [커뮤니티](https://www.getambassador.io/docs) 혹은 [상업적](https://www.getambassador.io/pro/) 지원을 제공하는 [Envoy](https://www.envoyproxy.io) 기반 인그레스 컨트롤러다. diff --git a/content/ko/docs/concepts/services-networking/service.md b/content/ko/docs/concepts/services-networking/service.md index ba0d78cf2f..b6a8448f06 100644 --- a/content/ko/docs/concepts/services-networking/service.md +++ b/content/ko/docs/concepts/services-networking/service.md @@ -184,17 +184,17 @@ ExternalName 서비스는 셀렉터가 없고 DNS명을 대신 사용하는 특수한 상황의 서비스이다. 자세한 내용은 이 문서 뒷부분의 [ExternalName](#externalname) 섹션을 참조한다. -### 엔드포인트 슬라이스 +### 엔드포인트슬라이스 {{< feature-state for_k8s_version="v1.17" state="beta" >}} -엔드포인트 슬라이스는 엔드포인트에 보다 확장 가능한 대안을 제공할 수 있는 -API 리소스이다. 개념적으로 엔드포인트와 매우 유사하지만, 엔드포인트 슬라이스를 +엔드포인트슬라이스는 엔드포인트에 보다 확장 가능한 대안을 제공할 수 있는 +API 리소스이다. 개념적으로 엔드포인트와 매우 유사하지만, 엔드포인트슬라이스를 사용하면 여러 리소스에 네트워크 엔드포인트를 분산시킬 수 있다. 기본적으로, -엔드포인트 슬라이스는 100개의 엔드포인트에 도달하면 "가득찬 것"로 간주되며, -추가 엔드포인트를 저장하기 위해서는 추가 엔드포인트 슬라이스가 +엔드포인트슬라이스는 100개의 엔드포인트에 도달하면 "가득찬 것"로 간주되며, +추가 엔드포인트를 저장하기 위해서는 추가 엔드포인트슬라이스가 생성된다. -엔드포인트 슬라이스는 [엔드포인트 슬라이스](/ko/docs/concepts/services-networking/endpoint-slices/)에서 +엔드포인트슬라이스는 [엔드포인트슬라이스](/ko/docs/concepts/services-networking/endpoint-slices/)에서 자세하게 설명된 추가적인 속성 및 기능을 제공한다. ## 가상 IP와 서비스 프록시 @@ -484,7 +484,7 @@ API에서 `엔드포인트` 레코드를 생성하고, DNS 구성을 수정하 `externalName` 필드의 컨텐츠 (예:`foo.bar.example.com`)에 맵핑한다. 어떤 종류의 프록시도 설정되어 있지 않다. {{< note >}} - `ExternalName` 유형을 사용하려면 CoreDNS 버전 1.7 이상이 필요하다. + `ExternalName` 유형을 사용하려면 kube-dns 버전 1.7 또는 CoreDNS 버전 1.7 이상이 필요하다. {{< /note >}} [인그레스](/ko/docs/concepts/services-networking/ingress/)를 사용하여 서비스를 노출시킬 수도 있다. 인그레스는 서비스 유형이 아니지만, 클러스터의 진입점 역할을 한다. 동일한 IP 주소로 여러 서비스를 노출시킬 수 있기 때문에 라우팅 규칙을 단일 리소스로 통합할 수 있다. @@ -548,6 +548,9 @@ status: 외부 로드 밸런서의 트래픽은 백엔드 파드로 전달된다. 클라우드 공급자는 로드 밸런싱 방식을 결정한다. +로드 밸런서 서비스 유형의 경우 두 개 이상의 포트가 정의된 경우, +모든 포트의 프로토콜이 동일해야 하고, 프로토콜은 `TCP`, `UDP` 그리고 +`SCTP` 중 하나여야 한다. 일부 클라우드 공급자는 `loadBalancerIP`를 지정할 수 있도록 허용한다. 이 경우, 로드 밸런서는 사용자 지정 `loadBalancerIP`로 생성된다. `loadBalancerIP` 필드가 지정되지 않으면, @@ -1100,21 +1103,15 @@ IPVS는 로드 밸런싱을 위해 설계되었고 커널-내부 해시 테이 ### TCP -{{< feature-state for_k8s_version="v1.0" state="stable" >}} - 모든 종류의 서비스에 TCP를 사용할 수 있으며, 이는 기본 네트워크 프로토콜이다. ### UDP -{{< feature-state for_k8s_version="v1.0" state="stable" >}} - 대부분의 서비스에 UDP를 사용할 수 있다. type=LoadBalancer 서비스의 경우, UDP 지원은 이 기능을 제공하는 클라우드 공급자에 따라 다르다. ### HTTP -{{< feature-state for_k8s_version="v1.1" state="stable" >}} - 클라우드 공급자가 이를 지원하는 경우, LoadBalancer 모드의 서비스를 사용하여 서비스의 엔드포인트로 전달하는 외부 HTTP / HTTPS 리버스 프록시를 설정할 수 있다. @@ -1126,8 +1123,6 @@ HTTP / HTTPS 서비스를 노출할 수도 있다. ### PROXY 프로토콜 -{{< feature-state for_k8s_version="v1.1" state="stable" >}} - 클라우드 공급자가 지원하는 경우에 (예: [AWS](/docs/concepts/cluster-administration/cloud-providers/#aws)), LoadBalancer 모드의 서비스를 사용하여 쿠버네티스 자체 외부에 로드 밸런서를 구성할 수 있으며, 이때 접두사가 @@ -1196,6 +1191,6 @@ kube-proxy는 유저스페이스 모드에 있을 때 SCTP 연결 관리를 지 * [서비스와 애플리케이션 연결](/docs/concepts/services-networking/connect-applications-service/) 알아보기 * [인그레스](/ko/docs/concepts/services-networking/ingress/)에 대해 알아보기 -* [엔드포인트 슬라이스](/ko/docs/concepts/services-networking/endpoint-slices/)에 대해 알아보기 +* [엔드포인트슬라이스](/ko/docs/concepts/services-networking/endpoint-slices/)에 대해 알아보기 {{% /capture %}} diff --git a/content/ko/docs/concepts/workloads/controllers/replicaset.md b/content/ko/docs/concepts/workloads/controllers/replicaset.md index 27f2dd359c..aedb0d03ef 100644 --- a/content/ko/docs/concepts/workloads/controllers/replicaset.md +++ b/content/ko/docs/concepts/workloads/controllers/replicaset.md @@ -73,7 +73,7 @@ kubectl describe rs/frontend ```shell Name: frontend Namespace: default -Selector: tier=frontend,tier in (frontend) +Selector: tier=frontend Labels: app=guestbook tier=frontend Annotations: @@ -132,7 +132,7 @@ metadata: name: frontend-9si5l namespace: default ownerReferences: - - apiVersion: extensions/v1beta1 + - apiVersion: apps/v1 blockOwnerDeletion: true controller: true kind: ReplicaSet @@ -257,7 +257,7 @@ REST API또는 `client-go` 라이브러리를 이용할 때는 -d 옵션으로 ` 예시: ```shell kubectl proxy --port=8080 -curl -X DELETE 'localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/frontend' \ +curl -X DELETE 'localhost:8080/apis/apps/v1/namespaces/default/replicasets/frontend' \ > -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Foreground"}' \ > -H "Content-Type: application/json" ``` @@ -269,7 +269,7 @@ REST API 또는 `client-go` 라이브러리를 이용할 때는 `propagationPoli 예시: ```shell kubectl proxy --port=8080 -curl -X DELETE 'localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/frontend' \ +curl -X DELETE 'localhost:8080/apis/apps/v1/namespaces/default/replicasets/frontend' \ > -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \ > -H "Content-Type: application/json" ``` diff --git a/content/ko/docs/concepts/workloads/pods/ephemeral-containers.md b/content/ko/docs/concepts/workloads/pods/ephemeral-containers.md index 6e831326c6..c394c58ab7 100644 --- a/content/ko/docs/concepts/workloads/pods/ephemeral-containers.md +++ b/content/ko/docs/concepts/workloads/pods/ephemeral-containers.md @@ -6,7 +6,7 @@ weight: 80 {{% capture overview %}} -{{< feature-state state="alpha" >}} +{{< feature-state state="alpha" for_k8s_version="v1.16" >}} 이 페이지는 임시 컨테이너에 대한 개요를 제공한다: 이 특별한 유형의 컨테이너는 트러블 슈팅과 같은 사용자가 시작한 작업을 완료하기위해 기존 {{< glossary_tooltip term_id="pod" >}} 에서 @@ -187,6 +187,7 @@ kubectl attach -it example-pod -c debugger 예를 들어, 임시 컨테이너에 붙은 이후에 디버거 컨테이너에서 `ps` 를 실행한다. ```shell +# "디버거" 임시 컨테이너 내부 쉘에서 이것을 실행한다. ps auxww ``` 다음과 유사하게 출력된다. diff --git a/content/ko/docs/concepts/workloads/pods/pod-lifecycle.md b/content/ko/docs/concepts/workloads/pods/pod-lifecycle.md index 3c8f9af995..813c111163 100644 --- a/content/ko/docs/concepts/workloads/pods/pod-lifecycle.md +++ b/content/ko/docs/concepts/workloads/pods/pod-lifecycle.md @@ -186,7 +186,7 @@ kubelet은 실행 중인 컨테이너들에 대해서 선택적으로 세 가지 ... ``` -* `Running`: 컨테이너가 이슈 없이 구동된다는 뜻이다. 컨테이너가 Running 상태가 되면, `postStart` 훅이 (존재한다면) 실행된다. 이 상태는 컨테이너가 언제 Running 상태에 돌입한 시간도 함께 출력된다. +* `Running`: 컨테이너가 이슈 없이 구동된다는 뜻이다. `postStart` 훅(있는 경우)은 컨테이너가 Running 상태가 되기 전에 실행된다. 이 상태는 컨테이너가 언제 Running 상태에 돌입한 시간도 함께 출력된다. ```yaml ... diff --git a/content/ko/docs/contribute/style/write-new-topic.md b/content/ko/docs/contribute/style/write-new-topic.md index 00cfa2db6c..d6c21c7bc9 100644 --- a/content/ko/docs/contribute/style/write-new-topic.md +++ b/content/ko/docs/contribute/style/write-new-topic.md @@ -115,8 +115,9 @@ YAML 파일과 같은 새로운 독립형 샘플 파일을 추가할 때 `/examples/` 의 하위 디렉토리 중 하나에 코드를 배치하자. 여기서 ``은 주제에 관한 언어이다. 문서 파일에서 `codenew` 단축 코드(shortcode)를 사용하자. -
{{< codenew file="<RELPATH>/my-example-yaml>" >}}
- +```none +{{/my-example-yaml>" */>}} +``` 여기서 `` 는 `examples` 디렉토리와 관련하여 포함될 파일의 경로이다. 다음 Hugo 단축 코드(shortcode)는 `/content/en/examples/pods/storage/gce-volume.yaml` 에 있는 YAML 파일을 참조한다. diff --git a/content/ko/docs/reference/glossary/cluster.md b/content/ko/docs/reference/glossary/cluster.md index 92f8eabd37..a4a42b32aa 100755 --- a/content/ko/docs/reference/glossary/cluster.md +++ b/content/ko/docs/reference/glossary/cluster.md @@ -4,14 +4,14 @@ id: cluster date: 2019-06-15 full_link: short_description: > - 쿠버네티스에서 관리하는 컨테이너화된 애플리케이션을 실행하는 노드라고 하는 기계의 집합. 클러스터는 최소 1개의 워커 노드와 최소 1개의 마스터 노드를 가진다. + 컨테이너화된 애플리케이션을 실행하는 노드라고 하는 워커 머신의 집합. 모든 클러스터는 최소 한 개의 워커 노드를 가진다. aka: tags: - fundamental - operation --- -쿠버네티스에서 관리하는 컨테이너화된 애플리케이션을 실행하는 노드라고 하는 기계의 집합. 클러스터는 최소 1개의 워커 노드와 최소 1개의 마스터 노드를 가진다. +컨테이너화된 애플리케이션을 실행하는 노드라고 하는 워커 머신의 집합. 모든 클러스터는 최소 한 개의 워커 노드를 가진다. -워커 노드는 애플리케이션의 구성요소인 파드를 호스트한다. 마스터 노드는 워커 노드와 클러스터 내 파드를 관리한다. 다수의 마스터 노드는 장애극복(failover)과 고가용성의 클러스터에서 사용한다. +워커 노드는 애플리케이션의 구성요소인 파드를 호스트한다. 컨트롤 플레인은 워커 노드와 클러스터 내 파드를 관리한다. 프로덕션 환경에서는 일반적으로 컨트롤 플레인이 여러 컴퓨터에 걸쳐 실행되고, 클러스터는 일반적으로 여러 노드를 실행하므로 내결함성과 고가용성이 제공된다. diff --git a/content/ko/docs/reference/glossary/container-runtime.md b/content/ko/docs/reference/glossary/container-runtime.md index 112282e178..47fd7031b1 100644 --- a/content/ko/docs/reference/glossary/container-runtime.md +++ b/content/ko/docs/reference/glossary/container-runtime.md @@ -15,7 +15,7 @@ tags: -쿠버네티스는 여러 컨테이너 런타임을 지원한다. [Docker](http://www.docker.com), -[containerd](https://containerd.io), [cri-o](https://cri-o.io/), -[rktlet](https://github.com/kubernetes-incubator/rktlet)과 -[Kubernetes CRI (컨테이너 런타임 인터페이스)](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/container-runtime-interface.md)를 구현한 모든 소프트웨어. +쿠버네티스는 여러 컨테이너 런타임을 지원한다. {{< glossary_tooltip term_id="docker">}}, +{{< glossary_tooltip term_id="containerd" >}}, {{< glossary_tooltip term_id="cri-o" >}} +그리고 [Kubernetes CRI (컨테이너 런타임 +인터페이스)](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/container-runtime-interface.md)를 구현한 모든 소프트웨어. diff --git a/content/ko/docs/reference/glossary/kube-controller-manager.md b/content/ko/docs/reference/glossary/kube-controller-manager.md index 41751f92f5..e327a6c285 100644 --- a/content/ko/docs/reference/glossary/kube-controller-manager.md +++ b/content/ko/docs/reference/glossary/kube-controller-manager.md @@ -4,7 +4,7 @@ id: kube-controller-manager date: 2018-04-12 full_link: /docs/reference/command-line-tools-reference/kube-controller-manager/ short_description: > - 컨트롤러를 구동하는 마스터 상의 컴포넌트. + {{< glossary_tooltip text="컨트롤러" term_id="controller" >}} 프로세스를 실행하는 컨트롤 플레인 컴포넌트. aka: tags: diff --git a/content/ko/docs/reference/glossary/kube-scheduler.md b/content/ko/docs/reference/glossary/kube-scheduler.md index d93c40bea7..a560832ef5 100644 --- a/content/ko/docs/reference/glossary/kube-scheduler.md +++ b/content/ko/docs/reference/glossary/kube-scheduler.md @@ -4,13 +4,13 @@ id: kube-scheduler date: 2018-04-12 full_link: /docs/reference/generated/kube-scheduler/ short_description: > - 노드가 배정되지 않은 새로 생성된 파드를 감지하고 그것이 구동될 노드를 선택하는 마스터 상의 컴포넌트. + 노드가 배정되지 않은 새로 생성된 파드를 감지하고, 실행할 노드를 선택하는 컨트롤 플레인 컴포넌트. aka: tags: - architecture --- - 노드가 배정되지 않은 새로 생성된 파드를 감지하고 그것이 구동될 노드를 선택하는 마스터 상의 컴포넌트. + 노드가 배정되지 않은 새로 생성된 파드를 감지하고, 실행할 노드를 선택하는 컨트롤 플레인 컴포넌트. diff --git a/content/ko/docs/reference/glossary/pod-lifecycle.md b/content/ko/docs/reference/glossary/pod-lifecycle.md index a435551e88..52f107ecb9 100644 --- a/content/ko/docs/reference/glossary/pod-lifecycle.md +++ b/content/ko/docs/reference/glossary/pod-lifecycle.md @@ -9,11 +9,11 @@ related: tags: - fundamental short-description: > - 파드가 라이프사이클 중 어느 단계(phase)에 있는지 표현하는 고수준의 요약이다. + 파드가 수명(lifetime) 동안 통과하는 상태의 순서이다. --- - 파드가 라이프사이클 중 어느 단계(phase)에 있는지 표현하는 고수준의 요약이다. + 파드가 수명(lifetime) 동안 통과하는 상태의 순서이다. -[파드 라이프사이클](/ko/docs/concepts/workloads/pods/pod-lifecycle/)은 파드가 라이프사이클 중 어느 단계에 있는지 표현하는 고수준의 요약이다. 파드의 `status` 필드는 [파드 스테이터스](/docs/reference/generated/kubernetes-api/v1.13/#podstatus-v1-core) 오브젝트이다. 그것은 `phase` 필드를 가지며, Running, Pending, Succeeded, Failed, Unknown, Completed, CrashLoopBackOff 중 하나의 단계(phase)를 보여준다. +[파드 라이프사이클](/ko/docs/concepts/workloads/pods/pod-lifecycle/)은 파드의 라이프사이클에 대한 고수준의 요약이다. 다섯 가지 파드 단계가 있다: Pending, Running, Succeeded, Failed, 그리고 Unknown. [파드 스테이터스](/docs/reference/generated/kubernetes-api/v1.13/#podstatus-v1-core)의 `phase` 필드에 파드 상태에 대한 자세한 설명이 요약되어 있다. diff --git a/content/ko/docs/reference/issues-security/security.md b/content/ko/docs/reference/issues-security/security.md index b52356cb18..234ec3c018 100644 --- a/content/ko/docs/reference/issues-security/security.md +++ b/content/ko/docs/reference/issues-security/security.md @@ -19,7 +19,7 @@ weight: 20 우리는 쿠버네티스 오픈소스 커뮤니티에 취약점을 보고하는 보안 연구원들과 사용자들에게 매우 감사하고 있다. 모든 보고서는 커뮤니티 자원 봉사자들에 의해 철저히 조사된다. -보고서를 작성하기 위해서는 보안 세부 내용과 [모든 쿠버네티스 버그 보고서](https://git.k8s.io/kubernetes/.github/ISSUE_TEMPLATE/bug-report.md)로부터 예상되는 세부 사항을 [security@kubernetes.io](mailto:security@kubernetes.io)로 이메일을 보낸다. +보고서를 작성하려면, [쿠버네티스 버그 현상금 프로그램](https://hackerone.com/kubernetes)에 취약점을 제출한다. 이를 통해 표준화된 응답시간으로 취약점을 분류하고 처리할 수 있다. 또한, 보안 세부 내용과 [모든 쿠버네티스 버그 보고서](https://git.k8s.io/kubernetes/.github/ISSUE_TEMPLATE/bug-report.md)로 부터 예상되는 세부사항을 [security@kubernetes.io](mailto:security@kubernetes.io)로 이메일을 보낸다. [제품 보안 위원회 구성원](https://git.k8s.io/security/security-release-process.md#product-security-committee-psc)의 GPG 키를 사용하여 이 목록으로 이메일을 암호화할 수 있다. GPG를 사용한 암호화는 공개할 필요가 없다. diff --git a/content/ko/docs/reference/kubectl/cheatsheet.md b/content/ko/docs/reference/kubectl/cheatsheet.md index 8c6e54aabb..3ea2a1e60b 100644 --- a/content/ko/docs/reference/kubectl/cheatsheet.md +++ b/content/ko/docs/reference/kubectl/cheatsheet.md @@ -191,6 +191,9 @@ kubectl get pods -o json | jq '.items[].spec.containers[].env[]?.valueFrom.secre # 타임스탬프로 정렬된 이벤트 목록 조회 kubectl get events --sort-by=.metadata.creationTimestamp + +# 매니페스트가 적용된 경우 클러스터의 현재 상태와 클러스터의 상태를 비교한다. +kubectl diff -f ./my-manifest.yaml ``` ## 리소스 업데이트 diff --git a/content/ko/docs/setup/_index.md b/content/ko/docs/setup/_index.md index 8e6bc5e668..668684fa03 100644 --- a/content/ko/docs/setup/_index.md +++ b/content/ko/docs/setup/_index.md @@ -79,7 +79,7 @@ card: | [Gardener](https://gardener.cloud/) | ✔ | ✔ | ✔ | ✔ | ✔ | [사용자 정의 확장](https://github.com/gardener/gardener/blob/master/docs/extensions/overview.md) | | [Giant Swarm](https://www.giantswarm.io/) | ✔ | ✔ | ✔ | | | [Google](https://cloud.google.com/) | [Google Kubernetes Engine (GKE)](https://cloud.google.com/kubernetes-engine/) | [Google Compute Engine (GCE)](https://cloud.google.com/compute/)|[GKE On-Prem](https://cloud.google.com/gke-on-prem/) | | | | | | | | -| [Hidora](https:/hidora.com/) | ✔ | ✔| ✔ | | | | | | | | +| [Hidora](https://hidora.com/) | ✔ | ✔| ✔ | | | | | | | | | [IBM](https://www.ibm.com/in-en/cloud) | [IBM Cloud Kubernetes Service](https://cloud.ibm.com/kubernetes/catalog/cluster)| |[IBM Cloud Private](https://www.ibm.com/in-en/cloud/private) | | | [Ionos](https://www.ionos.com/enterprise-cloud) | [Ionos Managed Kubernetes](https://www.ionos.com/enterprise-cloud/managed-kubernetes) | [Ionos Enterprise Cloud](https://www.ionos.com/enterprise-cloud) | | | [Kontena Pharos](https://www.kontena.io/pharos/) | |✔| ✔ | | | diff --git a/content/ko/docs/setup/best-practices/node-conformance.md b/content/ko/docs/setup/best-practices/node-conformance.md index 399e7f13a5..3aa27d96ea 100644 --- a/content/ko/docs/setup/best-practices/node-conformance.md +++ b/content/ko/docs/setup/best-practices/node-conformance.md @@ -73,7 +73,7 @@ sudo docker run -it --rm --privileged --net=host \ k8s.gcr.io/node-test:0.2 ``` -노드 적합성 테스트는 [노드 e2e 테스트](https://github.com/kubernetes/community/blob/{{< param "githubbranch" >}}/contributors/devel/sig-node/e2e-node-tests.md)를 컨테이너화한 버전이다. +노드 적합성 테스트는 [노드 e2e 테스트](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/e2e-node-tests.md)를 컨테이너화한 버전이다. 기본적으로, 모든 적합성 테스트를 실행한다. 이론적으로, 컨테이너와 필요한 볼륨을 적절히 설정했다면 어떤 노드 e2e 테스트도 수행할 수 있다. diff --git a/content/ko/docs/setup/learning-environment/minikube.md b/content/ko/docs/setup/learning-environment/minikube.md index 4c8df0c805..d66ada6ea8 100644 --- a/content/ko/docs/setup/learning-environment/minikube.md +++ b/content/ko/docs/setup/learning-environment/minikube.md @@ -1,5 +1,6 @@ --- title: Minikube로 쿠버네티스 설치 +weight: 30 content_template: templates/concept --- @@ -257,11 +258,7 @@ minikube start \ Docker 이미지를 'latest'가 아닌 다른 태그로 태그했는지 확인하고 이미지를 풀링할 때에는 그 태그를 이용한다. 혹시 이미지 태그 버전을 지정하지 않았다면, 기본값은 `:latest`이고 이미지 풀링 정책은 `Always`가 가정하나, 만약 기본 Docker 레지스트리(보통 DockerHub)에 해당 Docker 이미지 버전이 없다면 `ErrImagePull`의 결과가 나타날 것이다. {{< /note >}} -맥이나 리눅스 호스트에서 해당 Docker 데몬을 사용하려면 `docker-env command`를 쉘에서 사용해야 한다. - -```shell -eval $(minikube docker-env) -``` +맥이나 리눅스 호스트에서 해당 Docker 데몬을 사용하려면 `minikube docker-env` 에서 마지막 줄을 실행한다. 이제 개인의 맥/리눅스 머신 내 커멘드 라인에서 도커를 사용해서 Minikube VM 안의 도커 데몬과 통신할 수 있다. @@ -404,7 +401,7 @@ spec: | VirtualBox | Linux | /home | /hosthome | | VirtualBox | macOS | /Users | /Users | | VirtualBox | Windows | C://Users | /c/Users | -| VMware Fusion | macOS | /Users | /Users | +| VMware Fusion | macOS | /Users | /mnt/hgfs/Users | | Xhyve | macOS | /Users | /Users | ## 프라이빗 컨테이너 레지스트리 diff --git a/content/ko/docs/setup/production-environment/container-runtimes.md b/content/ko/docs/setup/production-environment/container-runtimes.md index b5758996af..c83a13327a 100644 --- a/content/ko/docs/setup/production-environment/container-runtimes.md +++ b/content/ko/docs/setup/production-environment/container-runtimes.md @@ -72,7 +72,7 @@ kubelet을 재시작 하는 것은 에러를 해결할 수 없을 것이다. # Docker CE 설치 ## 리포지터리 설정 ### apt가 HTTPS 리포지터리를 사용할 수 있도록 해주는 패키지 설치 -apt-get update && apt-get install \ +apt-get update && apt-get install -y \ apt-transport-https ca-certificates curl software-properties-common ### Docker의 공식 GPG 키 추가 @@ -85,7 +85,7 @@ add-apt-repository \ stable" ## Docker CE 설치. -apt-get update && apt-get install \ +apt-get update && apt-get install -y \ containerd.io=1.2.10-3 \ docker-ce=5:19.03.4~3-0~ubuntu-$(lsb_release -cs) \ docker-ce-cli=5:19.03.4~3-0~ubuntu-$(lsb_release -cs) @@ -113,14 +113,14 @@ systemctl restart docker # Docker CE 설치 ## 리포지터리 설정 ### 필요한 패키지 설치. -yum install yum-utils device-mapper-persistent-data lvm2 +yum install -y yum-utils device-mapper-persistent-data lvm2 ### Docker 리포지터리 추가 yum-config-manager --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo ## Docker CE 설치. -yum update && yum install \ +yum update -y && yum install -y \ containerd.io-1.2.10 \ docker-ce-19.03.4 \ docker-ce-cli-19.03.4 @@ -181,13 +181,13 @@ sysctl --system # 선행 조건 설치 apt-get update -apt-get install software-properties-common +apt-get install -y software-properties-common add-apt-repository ppa:projectatomic/ppa apt-get update # CRI-O 설치 -apt-get install cri-o-1.15 +apt-get install -y cri-o-1.15 {{< /tab >}} {{< tab name="CentOS/RHEL 7.4+" codelang="bash" >}} @@ -196,7 +196,7 @@ apt-get install cri-o-1.15 yum-config-manager --add-repo=https://cbs.centos.org/repos/paas7-crio-115-release/x86_64/os/ # CRI-O 설치 -yum install --nogpgcheck cri-o +yum install --nogpgcheck -y cri-o {{< /tab >}} {{< /tabs >}} @@ -270,7 +270,7 @@ systemctl restart containerd # containerd 설치 ## 리포지터리 설정 ### 필요한 패키지 설치 -yum install yum-utils device-mapper-persistent-data lvm2 +yum install -y yum-utils device-mapper-persistent-data lvm2 ### Docker 리포지터리 추가리 yum-config-manager \ @@ -278,7 +278,7 @@ yum-config-manager \ https://download.docker.com/linux/centos/docker-ce.repo ## containerd 설치 -yum update && yum install containerd.io +yum update -y && yum install -y containerd.io # containerd 설정 mkdir -p /etc/containerd diff --git a/content/ko/docs/setup/production-environment/tools/kops.md b/content/ko/docs/setup/production-environment/tools/kops.md index d4d801a406..f1c1ed4d2d 100644 --- a/content/ko/docs/setup/production-environment/tools/kops.md +++ b/content/ko/docs/setup/production-environment/tools/kops.md @@ -1,6 +1,6 @@ --- title: Kops로 쿠버네티스 설치하기 -content_template: templates/concept +content_template: templates/task weight: 20 --- @@ -9,7 +9,7 @@ weight: 20 이곳 빠른 시작에서는 사용자가 얼마나 쉽게 AWS에 쿠버네티스 클러스터를 설치할 수 있는지 보여준다. [`kops`](https://github.com/kubernetes/kops)라는 이름의 툴을 이용할 것이다. -kops는 강력한 프로비저닝 시스템인데, +kops는 자동화된 프로비저닝 시스템인데, * 완전 자동화된 설치 * DNS를 통해 클러스터들의 신원 확인 @@ -18,26 +18,30 @@ kops는 강력한 프로비저닝 시스템인데, * 고가용성 지원 - [high_availability.md](https://github.com/kubernetes/kops/blob/master/docs/operations/high_availability.md) 보기 * 직접 프로비저닝 하거나 또는 할 수 있도록 terraform 매니페스트를 생성 - [terraform.md](https://github.com/kubernetes/kops/blob/master/docs/terraform.md) 보기 -만약 클러스터를 구축하는데 있어 이런 방법이 사용자의 생각과 다르다면 일종의 블록처럼 [kubeadm](/docs/admin/kubeadm/)를 이용할 수도 있다. -kops는 kubeadmin 위에서도 잘 동작한다. +{{% /capture %}} + +{{% capture prerequisites %}} + +* [kubectl](/docs/tasks/tools/install-kubectl/)을 반드시 설치해야 한다. + +* 반드시 64-bit (AMD64 그리고 Intel 64)디바이스 아키텍쳐 위에서 `kops` 를 [설치](https://github.com/kubernetes/kops#installing) 한다. + +* [AWS 계정](https://docs.aws.amazon.com/polly/latest/dg/setting-up.html)이 있고 [IAM 키](https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html#access-keys-and-secret-access-keys)를 생성하고 [구성](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html#cli-quick-configuration) 해야 한다. {{% /capture %}} -{{% capture body %}} +{{% capture steps %}} ## 클러스터 구축 ### (1/5) kops 설치 -#### 요구사항 - -kops를 이용하기 위해서는 [kubectl](/docs/tasks/tools/install-kubectl/)이 설치되어 있어야 한다. - #### 설치 [releases page](https://github.com/kubernetes/kops/releases)에서 kops를 다운로드 한다(소스코드로부터 빌드하는것도 역시 어렵지 않다). -MacOS에서: +{{< tabs name="kops_installation" >}} +{{% tab name="macOS" %}} 최신 버전의 릴리즈를 다운받는 명령어: @@ -78,19 +82,19 @@ sudo mv kops-darwin-amd64 /usr/local/bin/kops brew update && brew install kops ``` -Linux에서: +{{% /tab %}} +{{% tab name="Linux" %}} + 최신 릴리즈를 다운로드 받는 명령어: ```shell curl -LO https://github.com/kubernetes/kops/releases/download/$(curl -s https://api.github.com/repos/kubernetes/kops/releases/latest | grep tag_name | cut -d '"' -f 4)/kops-linux-amd64 ``` -특정 버전을 다운로드 받는다면 다음을 변경한다. +특정 버전의 kops를 다운로드하려면 명령의 다음 부분을 특정 kops 버전으로 변경한다. ```shell $(curl -s https://api.github.com/repos/kubernetes/kops/releases/latest | grep tag_name | cut -d '"' -f 4) ``` -특정 버전의 명령 부분이다. - 예를 들어 kops 버전을 v1.15.0을 다운로드 하려면 다음을 입력한다. ```shell @@ -115,38 +119,58 @@ sudo mv kops-linux-amd64 /usr/local/bin/kops brew update && brew install kops ``` +{{% /tab %}} +{{< /tabs >}} + + ### (2/5) 클러스터에 사용할 route53 domain 생성 -kops는 디스커버리를 위해 클러스터 내외부에서 DNS를 이용하고 이를 통해 사용자는 쿠버네티스 API서버에 도달할 수 있다. + +kops는 클러스터 내부와 외부 모두에서 검색을 위해 DNS을 사용하기에 클라이언트에서 쿠버네티스 API 서버에 연결할 +수 있다. 이런 클러스터 이름에 kops는 명확한 견해을 가지는데: 반드시 유효한 DNS 이름이어야 한다. 이렇게 함으로써 -사용자는 클러스터를 헷갈리지 않을것이고, 동료들과 혼선없이 공유할 수 있으며, IP를 기억할 필요없이 접근할 수 있다. +사용자는 클러스터를 헷갈리지 않을것이고, 동료들과 혼선없이 공유할 수 있으며, +IP를 기억할 필요없이 접근할 수 있다. -그렇게 하고 있겠지만, 클러스터를 구분하기 위해 서브도메인을 활용할 수 있다. 예를 들어 `useast1.dev.example.com`을 이용한다면, API 서버 엔드포인트는 `api.useast1.dev.example.com`가 될 것이다. +그렇게 하고 있겠지만, 클러스터를 구분하기 위해 서브도메인을 활용할 수 있다. 예를 들어 +`useast1.dev.example.com`을 이용한다면, API 서버 엔드포인트는 `api.useast1.dev.example.com`가 될 것이다. -Route53 hosted zone은 서브도메인도 지원한다. 여러분의 hosted zone은 `useast1.dev.example.com`, `dev.example.com` 그리고 `example.com` 같은 것도 될 수 있다. -kops는 이것들 모두와 잘 동작하며, 사용자는 보통 조직적인 부분을 고려해 결정한다(예를 들어, 사용자가 `dev.example.com`하위에 레코드를 생성하는것은 허용되지만, +Route53 hosted zone은 서브도메인도 지원한다. 여러분의 hosted zone은 `useast1.dev.example.com`, +`dev.example.com` 그리고 `example.com` 같은 것도 될 수 있다. kops는 이것들 모두와 잘 동작하며, +사용자는 보통 조직적인 부분을 고려해 결정한다(예를 들어, 사용자가 `dev.example.com`하위에 레코드를 생성하는것은 허용되지만, `example.com`하위에는 그렇지 않을 수 있다). `dev.example.com`을 hosted zone으로 사용하고 있다고 가정해보자. 보통 사용자는 [일반적인 방법](http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/CreatingNewSubdomain.html) 에 따라 생성하거나 `aws route53 create-hosted-zone --name dev.example.com --caller-reference 1` 와 같은 커맨드를 이용한다. -그 후 도메인 내 레코드들을 확인할 수 있도록 상위 도메인내에 NS 레코드를 생성해야 한다. 여기서는, `dev` NS 레코드를 `example.com`에 생성한다. 만약 이것이 루트 도메인 네임이라면 이 NS 레코드들은 도메인 등록기관을 통해서 생성해야 한다(예를 들어, `example.com`는 `example.com`를 구매한 곳에서 설정 할 수 있다). -이 단계에서 문제가 되기 쉽다.(문제를 만드는 가장 큰 이유이다!) dig 툴을 실행해서 클러스터 설정이 정확한지 한번 더 확인 한다. +그 후 도메인 내 레코드들을 확인할 수 있도록 상위 도메인내에 NS 레코드를 생성해야 한다. 여기서는, +`dev` NS 레코드를 `example.com`에 생성한다. 만약 이것이 루트 도메인 네임이라면 이 NS 레코드들은 +도메인 등록기관을 통해서 생성해야 한다(예를 들어, `example.com`는 `example.com`를 구매한 곳에서 설정 할 수 있다). + +이 단계에서 문제가 되기 쉽다.(문제를 만드는 가장 큰 이유이다!) dig 툴을 실행해서 +클러스터 설정이 정확한지 한번 더 확인 한다. `dig NS dev.example.com` 당신의 hosted zone용으로 할당된 3~4개의 NS 레코드를 Route53에서 확인할 수 있어야 한다. ### (3/5) 클러스터 상태 저장용 S3 버킷 생성 -kops는 설치 이후에도 클러스터를 관리할 수 있다. 이를 위해 사용자가 생성한 클러스터의 상태나 사용하는 키 정보들을 지속적으로 추적해야 한다. 이 정보가 S3에 저장된다. + +kops는 설치 이후에도 클러스터를 관리할 수 있다. 이를 위해 사용자가 생성한 클러스터의 상태나 +사용하는 키 정보들을 지속적으로 추적해야 한다. 이 정보가 S3에 저장된다. 이 버킷의 접근은 S3 권한으로 제어한다. -다수의 클러스터는 동일한 S3 버킷을 이용할 수 있고, 사용자는 이 S3 버킷을 같은 클러스트를 운영하는 동료에게 공유할 수 있다. 하지만 이 S3 버킷에 접근 가능한 사람은 사용자의 모든 클러스터에 관리자 접근이 가능하게 되니, 운영팀 이외로 공유되지 않도록 해야 한다. +다수의 클러스터는 동일한 S3 버킷을 이용할 수 있고, 사용자는 이 S3 버킷을 같은 클러스트를 +운영하는 동료에게 공유할 수 있다. 하지만 이 S3 버킷에 접근 가능한 사람은 사용자의 +모든 클러스터에 관리자 접근이 가능하게 되니, 운영팀 이외로 +공유되지 않도록 해야 한다. -그래서 보통 한 운영팀 당 하나의 S3 버킷을 가지도록 하기도 한다.(그리고 종종 운영팀 이름은 위에서 언급한 hosted zone과 동일하게 짓기도 한다!) +그래서 보통 한 운영팀 당 하나의 S3 버킷을 가지도록 하기도 한다.(그리고 종종 운영팀 +이름은 위에서 언급한 hosted zone과 동일하게 짓기도 한다!) -우리 예제에서는, `dev.example.com`를 hosted zone으로 했으니 `clusters.dev.example.com`를 S3 버킷 이름으로 정하자. +우리 예제에서는, `dev.example.com`를 hosted zone으로 했으니 `clusters.dev.example.com`를 +S3 버킷 이름으로 정하자. * `AWS_PROFILE`를 선언한다. (AWS CLI 동작을 위해 다른 profile을 선택해야 할 경우) @@ -155,12 +179,16 @@ kops는 설치 이후에도 클러스터를 관리할 수 있다. 이를 위해 * `export KOPS_STATE_STORE=s3://clusters.dev.example.com` 하면, kops는 이 위치를 기본값으로 인식할 것이다. 이 부분을 bash profile등에 넣어두는것을 권장한다. + ### (4/5) 클러스터 설정 구성 + 클러스터 설정하려면, `kops create cluster` 를 실행한다: `kops create cluster --zones=us-east-1c useast1.dev.example.com` -kops는 클러스터에 사용될 설정을 생성할것이다. 여기서 주의할 점은 실제 클러스트 리소스가 아닌 _설정_ 만을 생성한다는 것에 주의하자 - 이 부분은 다음 단계에서 `kops update cluster` 으로 구성해볼 것이다. 그 때 만들어진 설정을 점검하거나 변경할 수 있다. +kops는 클러스터에 사용될 설정을 생성할것이다. 여기서 주의할 점은 실제 클러스트 리소스가 아닌 _설정_ +만을 생성한다는 것에 주의하자 - 이 부분은 다음 단계에서 `kops update cluster` 으로 +구성해볼 것이다. 그 때 만들어진 설정을 점검하거나 변경할 수 있다. 더 자세한 내용을 알아보기 위한 커맨드가 출력된다. @@ -169,7 +197,10 @@ kops는 클러스터에 사용될 설정을 생성할것이다. 여기서 주의 * 인스턴스 그룹 수정: `kops edit ig --name=useast1.dev.example.com nodes` * 마스터 인스턴스 그룹 수정: `kops edit ig --name=useast1.dev.example.com master-us-east-1c` -만약 kops사용이 처음이라면, 얼마 걸리지 않으니 이들을 시험해 본다. 인스턴스 그룹은 쿠버네티스 노드로 등록된 인스턴스의 집합을 말한다. AWS상에서는 auto-scaling-groups를 통해 만들어진다. 사용자는 여러개의 인스턴스 그룹을 관리할 수 있는데, 예를 들어, spot과 on-demand 인스턴스 조합 또는 GPU 와 non-GPU 인스턴스의 조합으로 구성할 수 있다. +만약 kops사용이 처음이라면, 얼마 걸리지 않으니 이들을 시험해 본다. 인스턴스 그룹은 +쿠버네티스 노드로 등록된 인스턴스의 집합을 말한다. AWS상에서는 auto-scaling-groups를 +통해 만들어진다. 사용자는 여러개의 인스턴스 그룹을 관리할 수 있는데, +예를 들어, spot과 on-demand 인스턴스 조합 또는 GPU 와 non-GPU 인스턴스의 조합으로 구성할 수 있다. ### (5/5) AWS에 클러스터 생성 @@ -179,31 +210,30 @@ kops는 클러스터에 사용될 설정을 생성할것이다. 여기서 주의 `kops update cluster useast1.dev.example.com --yes` 실행은 수 초 만에 되지만, 실제로 클러스터가 준비되기 전까지 수 분이 걸릴 수 있다. -언제든 `kops update cluster`로 클러스트 설정을 변경할 수 있다. 사용자가 변경한 클러스트 설정을 그대로 반영해 줄 것이며, 필요다하면 AWS 나 쿠버네티스를 재설정 해 줄것이다. +언제든 `kops update cluster`로 클러스터 설정을 변경할 수 있다. 사용자가 +변경한 클러스터 설정을 그대로 반영해 줄 것이며, 필요다하면 AWS 나 쿠버네티스를 재설정 해 줄것이다. -예를 들면, `kops edit ig nodes` 뒤에 `kops update cluster --yes`를 실행해 설정을 반영한다. 그리고 `kops rolling-update cluster`로 설정을 즉시 원복시킬 수 있다. - -`--yes`를 명시하지 않으면 `kops update cluster` 커맨드 후 어떤 설정이 변경될지가 표시된다. 운영계 클러스터 관리할 때 사용하기 좋다! +예를 들면, `kops edit ig nodes` 뒤에 `kops update cluster --yes`를 실행해 설정을 반영한다. +그리고 `kops rolling-update cluster`로 설정을 즉시 원복시킬 수 있다. +`--yes`를 명시하지 않으면 `kops update cluster` 커맨드 후 어떤 설정이 변경될지가 표시된다. +운영계 클러스터 관리할 때 사용하기 좋다! ### 다른 애드온 탐험 + [애드온 리스트](/docs/concepts/cluster-administration/addons/) 에서 쿠버네티스 클러스터용 로깅, 모니터링, 네트워크 정책, 시각화 & 제어 등을 포함한 다른 애드온을 확인해본다. ## 정리하기 * `kops delete cluster useast1.dev.example.com --yes` 로 클러스터를 삭제한다. -## Feedback - -* Slack Channel: [#kops-users](https://kubernetes.slack.com/messages/kops-users/) -* [GitHub Issues](https://github.com/kubernetes/kops/issues) - {{% /capture %}} {{% capture whatsnext %}} * 쿠버네티스 [개념](/docs/concepts/) 과 [`kubectl`](/docs/user-guide/kubectl-overview/)에 대해 더 알아보기. -* `kops` [고급 사용법](https://github.com/kubernetes/kops) 알아보기. -* 튜토리얼, 모범사례, 고급 설정 옵션을 위해 `kops` [문서](https://github.com/kubernetes/kops) 부분 보기. +* 튜토리얼, 모범사례 및 고급 구성 옵션에 대한 `kops` [고급 사용법](https://kops.sigs.k8s.io/)에 대해 더 자세히 알아본다. +* 슬랙(Slack)에서 `kops` 커뮤니티 토론을 할 수 있다: [커뮤니티 토론](https://github.com/kubernetes/kops#other-ways-to-communicate-with-the-contributors) +* 문제를 해결하거나 이슈를 제기하여 `kops` 에 기여한다. [깃헙 이슈](https://github.com/kubernetes/kops/issues) {{% /capture %}} diff --git a/content/ko/docs/tasks/administer-cluster/network-policy-provider/cilium-network-policy.md b/content/ko/docs/tasks/administer-cluster/network-policy-provider/cilium-network-policy.md index b0cba9681e..1b0c866d18 100644 --- a/content/ko/docs/tasks/administer-cluster/network-policy-provider/cilium-network-policy.md +++ b/content/ko/docs/tasks/administer-cluster/network-policy-provider/cilium-network-policy.md @@ -1,5 +1,4 @@ --- -reviewers: title: 네트워크 폴리시로 실리움(Cilium) 사용하기 content_template: templates/task weight: 20 @@ -8,7 +7,7 @@ weight: 20 {{% capture overview %}} 이 페이지는 어떻게 네트워크 폴리시(NetworkPolicy)로 실리움(Cilium)를 사용하는지 살펴본다. -실리움의 배경에 대해서는 [실리움 소개](https://cilium.readthedocs.io/en/stable/intro)를 읽어보자. +실리움의 배경에 대해서는 [실리움 소개](https://docs.cilium.io/en/stable/intro)를 읽어보자. {{% /capture %}} {{% capture prerequisites %}} @@ -22,35 +21,44 @@ weight: 20 실리움에 쉽게 친숙해지기 위해 Minikube에 실리움을 기본적인 데몬셋으로 설치를 수행하는 -[실리움 쿠버네티스 시작하기 안내](https://cilium.readthedocs.io/en/stable/gettingstarted/minikube/)를 따라 해볼 수 있다. +[실리움 쿠버네티스 시작하기 안내](https://docs.cilium.io/en/stable/gettingstarted/minikube/)를 따라 해볼 수 있다. -Minikube를 시작하려면 최소 버전으로 >= v0.33.1 이 필요하고, +Minikube를 시작하려면 최소 버전으로 >= v1.3.1 이 필요하고, 다음의 실행 파라미터로 실행한다. ```shell minikube version ``` ``` -minikube version: v0.33.1 +minikube version: v1.3.1 ``` ```shell minikube start --network-plugin=cni --memory=4096 ``` -Minikube에서 실리움의 데몬셋 구성과 Minikube에 배포된 etcd 인스턴스로 접속하는데 필요한 구성 뿐만 아니라 -RBAC 설정을 포함하는 필요한 구성을 -이 간단한 ``올인원`` YAML 파일로 배포할 수 있다. +BPF 파일시스템을 마운트한다 ```shell -kubectl create -f https://raw.githubusercontent.com/cilium/cilium/v1.5/examples/kubernetes/1.14/cilium-minikube.yaml +minikube ssh -- sudo mount bpffs -t bpf /sys/fs/bpf +``` + +Minikube에서 실리움의 데몬셋 구성과 적절한 RBAC 설정을 포함하는 필요한 구성을 +간단한 ``올인원`` YAML 파일로 배포할 수 있다. + +```shell +kubectl create -f https://raw.githubusercontent.com/cilium/cilium/v1.6/install/kubernetes/quick-install.yaml ``` ``` configmap/cilium-config created -daemonset.apps/cilium created -clusterrolebinding.rbac.authorization.k8s.io/cilium created -clusterrole.rbac.authorization.k8s.io/cilium created serviceaccount/cilium created +serviceaccount/cilium-operator created +clusterrole.rbac.authorization.k8s.io/cilium created +clusterrole.rbac.authorization.k8s.io/cilium-operator created +clusterrolebinding.rbac.authorization.k8s.io/cilium created +clusterrolebinding.rbac.authorization.k8s.io/cilium-operator created +daemonset.apps/cilium create +deployment.apps/cilium-operator created ``` 시작하기 안내서의 나머지 부분은 예제 애플리케이션을 이용하여 @@ -60,7 +68,7 @@ L3/L4(예, IP 주소 + 포트) 모두의 보안 정책 뿐만 아니라 L7(예, ## 실리움을 실 서비스 용도로 배포하기 실리움을 실 서비스 용도의 배포에 관련한 자세한 방법은 -[실리움 쿠버네티스 설치 안내](https://cilium.readthedocs.io/en/stable/kubernetes/intro/)를 살펴본다. +[실리움 쿠버네티스 설치 안내](https://docs.cilium.io/en/stable/kubernetes/intro/)를 살펴본다. 이 문서는 자세한 요구사항, 방법과 실제 데몬셋 예시를 포함한다. @@ -84,14 +92,8 @@ cilium-6rxbd 1/1 Running 0 1m ... ``` -알고 있어야 할 두 가지 주요 구성요소는 다음과 같다. - -- 먼저는 `cilium` 파드가 클러스터의 각 노드에서 운영되고, -노드의 파드로 보내고/받는 트래픽을 리눅스 BPF를 이용하여 네트워크 폴리시를 적용한다. -- 실 서비스에 배포하는 경우 실리움은 키-값 저장소(예, etcd)를 활용해야 한다. -[실리움 쿠버네티스 설치 안내](https://cilium.readthedocs.io/en/stable/kubernetes/intro/)에서 -키-값 저장소를 설치하는 방법과 실리움에서 이를 구성하는 필수 단계를 -제공할 것이다. +`cilium` 파드는 클러스터 각 노드에서 실행되며, 리눅스 BPF를 사용해서 +해당 노드의 파드에 대한 트래픽 네트워크 폴리시를 적용한다. {{% /capture %}} diff --git a/content/ko/docs/tasks/debug-application-cluster/resource-metrics-pipeline.md b/content/ko/docs/tasks/debug-application-cluster/resource-metrics-pipeline.md index 05b08113e7..9bddc81234 100644 --- a/content/ko/docs/tasks/debug-application-cluster/resource-metrics-pipeline.md +++ b/content/ko/docs/tasks/debug-application-cluster/resource-metrics-pipeline.md @@ -34,6 +34,16 @@ Horizontal Pod Autoscaler 같은 클러스터의 컨트롤러에서 결정을 이 API를 사용하려면 메트릭 서버를 클러스터에 배포해야 한다. 그렇지 않으면 사용할 수 없다. {{< /note >}} +## 리소스 사용량 측정 + +### CPU + +CPU는 일정 기간 동안 [CPU 코어](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#meaning-of-cpu)에서 평균 사용량으로 리포트된다. 이 값은 커널(리눅스와 윈도우 커널 모두)에서 제공하는 누적 CPU 카운터보다 높은 비율을 적용해서 얻는다. kubelet은 비율 계산에 사용할 윈도우를 선택한다. + +### 메모리 + +메모리는 메트릭이 수집된 순간 작업 집합으로 리포트 된다. 이상적인 환경에서 "작업 집합(working set)"은 압박(memory pressure)에서 풀려날 수 없는 사용 중인(in-use) 메모리의 양이다. 그러나 작업 집합의 계산은 호스트 OS에 따라 다르며, 일반적으로 휴리스틱스를 사용해서 평가한다. 쿠버네티스는 스왑(swap)을 지원하지 않기 때문에 모든 익명(파일로 백업되지 않은) 메모리를 포함한다. 호스트 OS가 항상 이러한 페이지를 회수할 수 없기 때문에 메트릭에는 일반적으로 일부 캐시된(파일 백업) 메모리도 포함된다. + ## 메트릭 서버 [메트릭 서버](https://github.com/kubernetes-incubator/metrics-server)는 클러스터 전역에서 리소스 사용량 데이터를 집계한다. diff --git a/content/ko/docs/tasks/manage-kubernetes-objects/declarative-config.md b/content/ko/docs/tasks/manage-kubernetes-objects/declarative-config.md index 83f787b152..d47b6e7f31 100644 --- a/content/ko/docs/tasks/manage-kubernetes-objects/declarative-config.md +++ b/content/ko/docs/tasks/manage-kubernetes-objects/declarative-config.md @@ -983,11 +983,11 @@ TODO(pwittrock): Why doesn't export remove the status field? Seems like it shou ```yaml selector: matchLabels: - controller-selector: "extensions/v1beta1/deployment/nginx" + controller-selector: "apps/v1/deployment/nginx" template: metadata: labels: - controller-selector: "extensions/v1beta1/deployment/nginx" + controller-selector: "apps/v1/deployment/nginx" ``` {{% capture whatsnext %}} diff --git a/content/ko/docs/tasks/manage-kubernetes-objects/imperative-config.md b/content/ko/docs/tasks/manage-kubernetes-objects/imperative-config.md index 1080064ff1..3fdd8ad12d 100644 --- a/content/ko/docs/tasks/manage-kubernetes-objects/imperative-config.md +++ b/content/ko/docs/tasks/manage-kubernetes-objects/imperative-config.md @@ -135,11 +135,11 @@ kubectl create -f --edit ```yaml selector: matchLabels: - controller-selector: "extensions/v1beta1/deployment/nginx" + controller-selector: "apps/v1/deployment/nginx" template: metadata: labels: - controller-selector: "extensions/v1beta1/deployment/nginx" + controller-selector: "apps/v1/deployment/nginx" ``` {{% /capture %}} diff --git a/content/ko/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough.md b/content/ko/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough.md index 27ae2c2f52..418ebb17dc 100644 --- a/content/ko/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough.md +++ b/content/ko/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough.md @@ -74,7 +74,7 @@ deployment.apps/php-apache created 다음 명령어는 첫 번째 단계에서 만든 php-apache 디플로이먼트 파드의 개수를 1부터 10 사이로 유지하는 Horizontal Pod Autoscaler를 생성한다. 간단히 얘기하면, HPA는 (디플로이먼트를 통한) 평균 CPU 사용량을 50%로 유지하기 위하여 레플리카의 개수를 늘리고 줄인다. -[kubectl run](https://github.com/kubernetes/kubernetes/blob/{{< param "githubbranch" >}}/docs/user-guide/kubectl/kubectl_run.md)으로 각 파드는 200 밀리코어까지 요청할 수 있고, +(kubectl run으로 각 파드는 200 밀리코어까지 요청할 수 있고, 따라서 여기서 말하는 평균 CPU 사용은 100 밀리코어를 말한다). 이에 대한 자세한 알고리즘은 [여기](/docs/tasks/run-application/horizontal-pod-autoscale/#algorithm-details)를 참고하기 바란다. diff --git a/content/ko/docs/tasks/run-application/horizontal-pod-autoscale.md b/content/ko/docs/tasks/run-application/horizontal-pod-autoscale.md index e3ba3cf282..3f40a1b22b 100644 --- a/content/ko/docs/tasks/run-application/horizontal-pod-autoscale.md +++ b/content/ko/docs/tasks/run-application/horizontal-pod-autoscale.md @@ -41,28 +41,28 @@ Horizontal Pod Autoscaler는 컨트롤러 또는 사용자 지정 메트릭 API(다른 모든 메트릭 용)에서 메트릭을 가져온다. * 파드 단위 리소스 메트릭(예 : CPU)의 경우 컨트롤러는 HorizontalPodAutoscaler가 -대상으로하는 각 파드에 대한 리소스 메트릭 API에서 메트릭을 가져온다. -그런 다음, 목표 사용률 값이 설정되면, 컨트롤러는 각 파드의 -컨테이너에 대한 동등한 자원 요청을 퍼센트 단위로 하여 사용률 값을 -계산한다. 대상 원시 값이 설정된 경우 원시 메트릭 값이 직접 사용된다. -그리고, 컨트롤러는 모든 대상 파드에서 사용된 사용률의 평균 또는 원시 값(지정된 -대상 유형에 따라 다름)을 가져와서 원하는 레플리카의 개수를 스케일하는데 -사용되는 비율을 생성한다. + 대상으로하는 각 파드에 대한 리소스 메트릭 API에서 메트릭을 가져온다. + 그런 다음, 목표 사용률 값이 설정되면, 컨트롤러는 각 파드의 + 컨테이너에 대한 동등한 자원 요청을 퍼센트 단위로 하여 사용률 값을 + 계산한다. 대상 원시 값이 설정된 경우 원시 메트릭 값이 직접 사용된다. + 그리고, 컨트롤러는 모든 대상 파드에서 사용된 사용률의 평균 또는 원시 값(지정된 + 대상 유형에 따라 다름)을 가져와서 원하는 레플리카의 개수를 스케일하는데 + 사용되는 비율을 생성한다. -파드의 컨테이너 중 일부에 적절한 리소스 요청이 설정되지 않은 경우, -파드의 CPU 사용률은 정의되지 않으며, 따라서 오토스케일러는 -해당 메트릭에 대해 아무런 조치도 취하지 않는다. 오토스케일링 -알고리즘의 작동 방식에 대한 자세한 내용은 아래 [알고리즘 세부 정보](#알고리즘-세부-정보) -섹션을 참조하기 바란다. + 파드의 컨테이너 중 일부에 적절한 리소스 요청이 설정되지 않은 경우, + 파드의 CPU 사용률은 정의되지 않으며, 따라서 오토스케일러는 + 해당 메트릭에 대해 아무런 조치도 취하지 않는다. 오토스케일링 + 알고리즘의 작동 방식에 대한 자세한 내용은 아래 [알고리즘 세부 정보](#알고리즘-세부-정보) + 섹션을 참조하기 바란다. * 파드 단위 사용자 정의 메트릭의 경우, 컨트롤러는 사용률 값이 아닌 원시 값을 사용한다는 점을 -제외하고는 파드 단위 리소스 메트릭과 유사하게 작동한다. + 제외하고는 파드 단위 리소스 메트릭과 유사하게 작동한다. * 오브젝트 메트릭 및 외부 메트릭의 경우, 문제의 오브젝트를 표현하는 -단일 메트릭을 가져온다. 이 메트릭은 목표 값과 -비교되어 위와 같은 비율을 생성한다. `autoscaling/v2beta2` API -버전에서는, 비교가 이루어지기 전에 해당 값을 파드의 개수로 -선택적으로 나눌 수 있다. + 단일 메트릭을 가져온다. 이 메트릭은 목표 값과 + 비교되어 위와 같은 비율을 생성한다. `autoscaling/v2beta2` API + 버전에서는, 비교가 이루어지기 전에 해당 값을 파드의 개수로 + 선택적으로 나눌 수 있다. HorizontalPodAutoscaler는 보통 일련의 API 집합(`metrics.k8s.io`, `custom.metrics.k8s.io`, `external.metrics.k8s.io`)에서 메트릭을 가져온다. `metrics.k8s.io` API는 대개 별도로 @@ -154,10 +154,17 @@ HorizontalPodAutoscaler에 여러 메트릭이 지정된 경우, 이 계산은 큰 값이 선택된다. 이러한 메트릭 중 어떠한 것도 원하는 레플리카 수로 변환할 수 없는 경우(예 : 메트릭 API에서 메트릭을 가져오는 중 오류 발생) 스케일을 건너뛴다. +이는 하나 이상의 메트릭이 +현재 값보다 높은 `desiredReplicas` 을 제공하는 경우 +HPA가 여전히 확장할 수 있음을 의미한다. -마지막으로, HPA가 목표를 스케일하기 직전에 스케일 권장 사항이 기록된다. 컨트롤러는 -구성 가능한 창(window) 내에서 가장 높은 권장 사항을 선택하도록 해당 창 내의 -모든 권장 사항을 고려한다. 이 값은 `--horizontal-pod-autoscaler-downscale-stabilization` 플래그를 사용하여 설정할 수 있고, 기본 값은 5분이다. +마지막으로, HPA가 목표를 스케일하기 직전에 스케일 권장 사항이 +기록된다. 컨트롤러는 구성 가능한 창(window) 내에서 가장 높은 권장 +사항을 선택하도록 해당 창 내의 모든 권장 사항을 고려한다. 이 값은 +`--horizontal-pod-autoscaler-downscale-stabilization` 플래그 또는 HPA 오브젝트 +동작 `behavior.scaleDown.stabilizationWindowSeconds` ([구성가능한 +스케일링 동작 지원](#구성가능한-스케일링-동작-지원)을 본다)을 +사용하여 설정할 수 있고, 기본 값은 5분이다. 즉, 스케일 다운이 점진적으로 발생하여 급격히 변동하는 메트릭 값의 영향을 완만하게 한다. @@ -206,9 +213,6 @@ Horizontal Pod Autoscaler를 사용하여 레플리카 그룹의 스케일을 평가된 메트릭의 동적인 특징 때문에 레플리카 수가 자주 변동할 수 있다. 이것은 때로는 *스래싱 (thrashing)* 이라고도 한다. -v1.6부터 클러스터 운영자는 `kube-controller-manager` 구성 -요소의 플래그로 노출된 글로벌 HPA 설정을 조정하여 이 문제를 완화할 수 있다. - v1.12부터는 새로운 알고리즘 업데이트가 업스케일 지연에 대한 필요성을 제거하였다. @@ -225,6 +229,11 @@ v1.12부터는 새로운 알고리즘 업데이트가 업스케일 지연에 대 있다. {{< /note >}} +v1.17 부터 v2beta2 API 필드에서 `behavior.scaleDown.stabilizationWindowSeconds` +를 설정하여 다운스케일 안정화 창을 HPA별로 설정할 수 있다. +[구성가능한 스케일링 +동작 지원](#구성가능한-스케일링-동작-지원)을 본다. + ## 멀티 메트릭을 위한 지원 Kubernetes 1.6은 멀티 메트릭을 기반으로 스케일링을 지원한다. `autoscaling/v2beta2` API @@ -275,6 +284,154 @@ API에 접속하려면 클러스터 관리자는 다음을 확인해야 한다. 어떻게 사용하는지에 대한 예시는 [커스텀 메트릭 사용하는 작업 과정](/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#autoscaling-on-multiple-metrics-and-custom-metrics)과 [외부 메트릭스 사용하는 작업 과정](/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#autoscaling-on-metrics-not-related-to-kubernetes-objects)을 참조한다. +## 구성가능한 스케일링 동작 지원 + +[v1.17](https://github.com/kubernetes/enhancements/blob/master/keps/sig-autoscaling/20190307-configurable-scale-velocity-for-hpa.md) +부터 `v2beta2` API는 HPA `behavior` 필드를 통해 +스케일링 동작을 구성할 수 있다. +동작은 `behavior` 필드 아래의 `scaleUp` 또는 `scaleDown` +섹션에서 스케일링 업과 다운을 위해 별도로 지정된다. 안정화 윈도우는 +스케일링 대상에서 레플리카 수의 플래핑(flapping)을 방지하는 +양방향에 대해 지정할 수 있다. 마찬가지로 스케일링 정책을 지정하면 +스케일링 중 레플리카 변경 속도를 제어할 수 있다. + +### 스케일링 정책 + +스펙의 `behavior` 섹션에 하나 이상의 스케일링 폴리시를 지정할 수 있다. +폴리시가 여러 개 지정된 경우 가장 많은 양의 변경을 +허용하는 정책이 기본적으로 선택된 폴리시이다. 다음 예시는 스케일 다운 중 이 +동작을 보여준다. + +```yaml +behavior: + scaleDown: + policies: + - type: Pods + value: 4 + periodSeconds: 60 + - type: Percent + value: 10 + periodSeconds: 60 +``` + +파드 수가 40개를 초과하면 두 번째 폴리시가 스케일링 다운에 사용된다. +예를 들어 80개의 레플리카가 있고 대상을 10개의 레플리카로 축소해야 하는 +경우 첫 번째 단계에서 8개의 레플리카가 스케일 다운 된다. 레플리카의 수가 72개일 때 +다음 반복에서 파드의 10%는 7.2 이지만, 숫자는 8로 올림된다. 오토스케일러 컨트롤러의 +각 루프에서 변경될 파드의 수는 현재 레플리카의 수에 따라 재계산된다. 레플리카의 수가 40 +미만으로 떨어지면 첫 번째 폴리시 _(파드들)_ 가 적용되고 한번에 +4개의 레플리카가 줄어든다. + +`periodSeconds` 는 폴리시가 참(true)으로 유지되어야 하는 기간을 나타낸다. +첫 번째 정책은 1분 내에 최대 4개의 레플리카를 스케일 다운할 수 있도록 허용한다. +두 번째 정책은 현재 레플리카의 최대 10%를 1분 내에 스케일 다운할 수 있도록 허용한다. + +확장 방향에 대해 `selectPolicy` 필드를 확인하여 폴리시 선택을 변경할 수 있다. +레플리카의 수를 최소로 변경할 수 있는 폴리시를 선택하는 `최소(Min)`로 값을 설정한다. +값을 `Disabled` 로 설정하면 해당 방향으로 스케일링이 완전히 +비활성화 된다. + +### 안정화 윈도우 + +안정화 윈도우는 스케일링에 사용되는 메트릭이 계속 변동할 때 레플리카의 플래핑을 +다시 제한하기 위해 사용된다. 안정화 윈도우는 스케일링을 방지하기 위해 과거부터 +계산된 의도한 상태를 고려하는 오토스케일링 알고리즘에 의해 사용된다. +다음의 예시에서 `scaleDown` 에 대해 안정화 윈도우가 지정되어있다. + +```yaml +scaleDown: + stabilizationWindowSeconds: 300 +``` + +메트릭이 대상을 축소해야하는 것을 나타내는 경우 알고리즘은 +이전에 계산된 의도한 상태를 살펴보고 지정된 간격의 최고 값을 사용한다. +위의 예시에서 지난 5분 동안 모든 의도한 상태가 고려된다. + +### 기본 동작 + +사용자 지정 스케일링을 사용하려면 일부 필드를 지정해야 한다. 사용자 정의해야 +하는 값만 지정할 수 있다. 이러한 사용자 지정 값은 기본값과 병합된다. 기본값은 HPA +알고리즘의 기존 동작과 일치한다. + +```yaml +behavior: + scaleDown: + stabilizationWindowSeconds: 300 + policies: + - type: Percent + value: 100 + periodSeconds: 15 + scaleUp: + stabilizationWindowSeconds: 0 + policies: + - type: Percent + value: 100 + periodSeconds: 15 + - type: Pods + value: 4 + periodSeconds: 15 + selectPolicy: Max +``` +안정화 윈도우의 스케일링 다운의 경우 _300_ 초(또는 제공된 +경우`--horizontal-pod-autoscaler-downscale-stabilization` 플래그의 값)이다. 스케일링 다운에서는 현재 +실행 중인 레플리카의 100%를 제거할 수 있는 단일 정책만 있으며, 이는 스케일링 +대상을 최소 허용 레플리카로 축소할 수 있음을 의미한다. +스케일링 업에는 안정화 윈도우가 없다. 메트릭이 대상을 스케일 업해야 한다고 표시된다면 대상이 즉시 스케일 업된다. +두 가지 폴리시가 있다. HPA가 정상 상태에 도달 할 때까지 15초 마다 +4개의 파드 또는 현재 실행 중인 레플리카의 100% 가 추가된다. + +### 예시: 다운스케일 안정화 윈도우 변경 + +사용자 지정 다운스케일 안정화 윈도우를 1분 동안 제공하기 위해 +다음 동작이 HPA에 추가된다. + +```yaml +behavior: + scaleDown: + stabilizationWindowSeconds: 60 +``` + +### 예시: 스케일 다운 비율 제한 + +HPA에 의해 파드가 제거되는 속도를 분당 10%로 제한하기 위해 +다음 동작이 HPA에 추가된다. + +```yaml +behavior: + scaleDown: + policies: + - type: Percent + value: 10 + periodSeconds: 60 +``` + +마지막으로 5개의 파드를 드롭하기 위해 다른 폴리시를 추가하고, 최소 선택 +전략을 추가할 수 있다. + +```yaml +behavior: + scaleDown: + policies: + - type: Percent + value: 10 + periodSeconds: 60 + - type: Pods + value: 5 + periodSeconds: 60 + selectPolicy: Max +``` + +### 예시: 스케일 다운 비활성화 + +`selectPolicy` 의 `Disabled` 값은 주어진 방향으로의 스케일링을 끈다. +따라서 다운 스케일링을 방지하기 위해 다음 폴리시가 사용된다. + +```yaml +behavior: + scaleDown: + selectPolicy: Disabled +``` + {{% /capture %}} {{% capture whatsnext %}} diff --git a/content/ko/docs/tutorials/hello-minikube.md b/content/ko/docs/tutorials/hello-minikube.md index 5c7470ef63..e24b887509 100644 --- a/content/ko/docs/tutorials/hello-minikube.md +++ b/content/ko/docs/tutorials/hello-minikube.md @@ -169,7 +169,7 @@ Katacode는 무료로 브라우저에서 쿠버네티스 환경을 제공한다. ## 애드온 사용하기 -Minikube에는 활성화하거나 비활성화 할 수 있고 로컬 쿠버네티스 환경에서 접속해 볼 수 있는 내장 애드온 셋이 있다. +Minikube에는 활성화하거나 비활성화 할 수 있고 로컬 쿠버네티스 환경에서 접속해 볼 수 있는 내장 {{< glossary_tooltip text="애드온" term_id="addons" >}} 셋이 있다. 1. 현재 지원하는 애드온 목록을 확인한다. @@ -186,7 +186,6 @@ Minikube에는 활성화하거나 비활성화 할 수 있고 로컬 쿠버네 efk: disabled freshpod: disabled gvisor: disabled - heapster: disabled helm-tiller: disabled ingress: disabled ingress-dns: disabled @@ -200,16 +199,16 @@ Minikube에는 활성화하거나 비활성화 할 수 있고 로컬 쿠버네 storage-provisioner-gluster: disabled ``` -2. 한 애드온을 활성화 한다. 예를 들어 `heapster` +2. 한 애드온을 활성화 한다. 예를 들어 `metrics-server` ```shell - minikube addons enable heapster + minikube addons enable metrics-server ``` 다음과 유사하게 출력된다. ``` - heapster was successfully enabled + metrics-server was successfully enabled ``` 3. 방금 생성한 파드와 서비스를 확인한다. @@ -224,7 +223,7 @@ Minikube에는 활성화하거나 비활성화 할 수 있고 로컬 쿠버네 NAME READY STATUS RESTARTS AGE pod/coredns-5644d7b6d9-mh9ll 1/1 Running 0 34m pod/coredns-5644d7b6d9-pqd2t 1/1 Running 0 34m - pod/heapster-9jttx 1/1 Running 0 26s + pod/metrics-server-67fb648c5 1/1 Running 0 26s pod/etcd-minikube 1/1 Running 0 34m pod/influxdb-grafana-b29w8 2/2 Running 0 26s pod/kube-addon-manager-minikube 1/1 Running 0 34m @@ -235,22 +234,22 @@ Minikube에는 활성화하거나 비활성화 할 수 있고 로컬 쿠버네 pod/storage-provisioner 1/1 Running 0 34m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE - service/heapster ClusterIP 10.96.241.45 80/TCP 26s + service/metrics-server ClusterIP 10.96.241.45 80/TCP 26s service/kube-dns ClusterIP 10.96.0.10 53/UDP,53/TCP 34m service/monitoring-grafana NodePort 10.99.24.54 80:30002/TCP 26s service/monitoring-influxdb ClusterIP 10.111.169.94 8083/TCP,8086/TCP 26s ``` -4. `heapster` 비활성화 +4. `metrics-server` 비활성화 ```shell - minikube addons disable heapster + minikube addons disable metrics-server ``` 다음과 유사하게 출력된다. ``` - heapster was successfully disabled + metrics-server was successfully disabled ``` ## 제거하기 diff --git a/content/ko/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro.html b/content/ko/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro.html index 5c285b65ef..95c22577fd 100644 --- a/content/ko/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro.html +++ b/content/ko/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro.html @@ -99,7 +99,7 @@ weight: 10

애플리케이션을 쿠버네티스에 배포한다는 것은, 마스터에 애플리케이션 컨테이너를 구동하라고 지시하는 것이다. 마스터는 컨테이너를 클러스터의 어느 노드에 구동시킬지를 스케줄한다. 노드는 마스터가 - 제공하는 쿠버네티스 API를 통해서 마스터와 통신한다. 최종 사용자도 쿠버네티스 API를 직접 + 제공하는 쿠버네티스 API를 통해서 마스터와 통신한다. 최종 사용자도 쿠버네티스 API를 직접 사용해서 클러스터와 상호작용할 수 있다.

쿠버네티스 클러스터는 물리 및 가상 머신 모두에 설치될 수 있다. 쿠버네티스 개발을 시작하려면 diff --git a/content/ko/docs/tutorials/kubernetes-basics/expose/expose-intro.html b/content/ko/docs/tutorials/kubernetes-basics/expose/expose-intro.html index 1c763fbd70..f8cf20216d 100644 --- a/content/ko/docs/tutorials/kubernetes-basics/expose/expose-intro.html +++ b/content/ko/docs/tutorials/kubernetes-basics/expose/expose-intro.html @@ -35,7 +35,7 @@ weight: 10

비록 각 파드들이 고유의 IP를 갖고 있기는 하지만, 그 IP들은 서비스의 도움없이 클러스터 외부로 노출되어질 수 없다. 서비스들은 여러분의 애플리케이션들에게 트래픽이 실릴 수 있도록 허용해준다. 서비스들은 ServiceSpec에서 type을 지정함으로써 다양한 방식들로 노출시킬 수 있다:

  • ClusterIP (기본값) - 클러스터 내에서 내부 IP 에 대해 서비스를 노출해준다. 이 방식은 오직 클러스터 내에서만 서비스가 접근될 수 있도록 해준다.
  • -
  • NodePort - NAT가 이용되는 클러스터 내에서 각각 선택된 노드들의 동일한 포트에 서비스를 노출시켜준다. <NodeIP>:<NodePort>를 이용하여 클러스터 외부로부터 서비스가 접근할 수 있도록 해준다. CluserIP의 상위 집합이다.
  • +
  • NodePort - NAT가 이용되는 클러스터 내에서 각각 선택된 노드들의 동일한 포트에 서비스를 노출시켜준다. <NodeIP>:<NodePort>를 이용하여 클러스터 외부로부터 서비스가 접근할 수 있도록 해준다. ClusterIP의 상위 집합이다.
  • LoadBalancer - (지원 가능한 경우) 기존 클라우드에서 외부용 로드밸런서를 생성하고 서비스에 고정된 공인 IP를 할당해준다. NodePort의 상위 집합이다.
  • ExternalName - 이름으로 CNAME 레코드를 반환함으로써 임의의 이름(스펙에서 externalName으로 명시)을 이용하여 서비스를 노출시켜준다. 프록시는 사용되지 않는다. 이 방식은 kube-dns 버전 1.7 이상에서 지원 가능하다.
diff --git a/content/ko/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume.md b/content/ko/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume.md index 71919aad75..1f419fdaf3 100644 --- a/content/ko/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume.md +++ b/content/ko/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume.md @@ -113,13 +113,13 @@ EOF 3. 두 파일을 `kustomization.yaml`에 추가하자. - ```shell - cat <>./kustomization.yaml - resources: - - mysql-deployment.yaml - - wordpress-deployment.yaml - EOF - ``` +```shell +cat <>./kustomization.yaml +resources: + - mysql-deployment.yaml + - wordpress-deployment.yaml +EOF +``` ## 적용하고 확인하기 `kustomization.yaml`은 WordPress 사이트와 MySQL 데이터베이스를 배포하는 모든 리소스를 포함한다. diff --git a/content/ko/examples/minikube/Dockerfile b/content/ko/examples/minikube/Dockerfile index 1fe745295a..dd58cb7e75 100644 --- a/content/ko/examples/minikube/Dockerfile +++ b/content/ko/examples/minikube/Dockerfile @@ -1,4 +1,4 @@ FROM node:6.14.2 EXPOSE 8080 COPY server.js . -CMD node server.js +CMD [ "node", "server.js" ] diff --git a/content/ko/examples/pods/pod-nginx.yaml b/content/ko/examples/pods/pod-nginx.yaml new file mode 100644 index 0000000000..134ddae2aa --- /dev/null +++ b/content/ko/examples/pods/pod-nginx.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx + labels: + env: test +spec: + containers: + - name: nginx + image: nginx + imagePullPolicy: IfNotPresent + nodeSelector: + disktype: ssd diff --git a/content/ko/examples/pods/pod-with-node-affinity.yaml b/content/ko/examples/pods/pod-with-node-affinity.yaml new file mode 100644 index 0000000000..253d2b21ea --- /dev/null +++ b/content/ko/examples/pods/pod-with-node-affinity.yaml @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Pod +metadata: + name: with-node-affinity +spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/e2e-az-name + operator: In + values: + - e2e-az1 + - e2e-az2 + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + preference: + matchExpressions: + - key: another-node-label-key + operator: In + values: + - another-node-label-value + containers: + - name: with-node-affinity + image: k8s.gcr.io/pause:2.0 \ No newline at end of file diff --git a/content/ko/examples/pods/pod-with-pod-affinity.yaml b/content/ko/examples/pods/pod-with-pod-affinity.yaml new file mode 100644 index 0000000000..35e645ef1f --- /dev/null +++ b/content/ko/examples/pods/pod-with-pod-affinity.yaml @@ -0,0 +1,29 @@ +apiVersion: v1 +kind: Pod +metadata: + name: with-pod-affinity +spec: + affinity: + podAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: security + operator: In + values: + - S1 + topologyKey: failure-domain.beta.kubernetes.io/zone + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: security + operator: In + values: + - S2 + topologyKey: failure-domain.beta.kubernetes.io/zone + containers: + - name: with-pod-affinity + image: k8s.gcr.io/pause:2.0 diff --git a/content/ko/includes/task-tutorial-prereqs.md b/content/ko/includes/task-tutorial-prereqs.md index 762d3210d7..70d2196773 100644 --- a/content/ko/includes/task-tutorial-prereqs.md +++ b/content/ko/includes/task-tutorial-prereqs.md @@ -1,5 +1,7 @@ -쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 합니다. -만약, 클러스터를 이미 가지고 있지 않다면, [Minikube](/docs/setup/minikube)를 사용해서 만들거나, +쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 +통신할 수 있도록 설정되어 있어야 합니다. +만약, 아직 클러스터를 가지고 있지 않다면, +[Minikube](/docs/setup/learning-environment/minikube/)를 사용해서 만들거나, 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있습니다: * [Katacoda](https://www.katacoda.com/courses/kubernetes/playground) From 57cdc4cbabee2dd710a606c23c4115394359ee49 Mon Sep 17 00:00:00 2001 From: xieyanker Date: Sat, 15 Feb 2020 14:31:27 +0800 Subject: [PATCH 030/111] hidden original annotation (#19126) --- content/zh/docs/concepts/containers/images.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/content/zh/docs/concepts/containers/images.md b/content/zh/docs/concepts/containers/images.md index 654512ad45..d0cf178b3e 100644 --- a/content/zh/docs/concepts/containers/images.md +++ b/content/zh/docs/concepts/containers/images.md @@ -618,6 +618,7 @@ common use cases and suggested solutions. - 使用 Docker hub 上的公有镜像 - 无需配置 - 在 GCE/GKE 上会自动使用高稳定性和高速的 Docker hub 的本地 mirror + -上述例子使用到的 `effect` 的一个值 `NoSchedule`,您也可以使用另外一个值 `PreferNoSchedule`。这是“优化”或“软”版本的 `NoSchedule` ——系统会*尽量*避免将 pod 调度到存在其不能容忍 taint 的节点上,但这不是强制的。`effect` 的值还可以设置为 `NoExecute` ,下文会详细描述这个值。 +上述例子使用到的 `effect` 的一个值 `NoSchedule`,您也可以使用另外一个值 `PreferNoSchedule`。这是“优化”或“软”版本的 `NoSchedule` ——系统会 *尽量* 避免将 pod 调度到存在其不能容忍 taint 的节点上,但这不是强制的。`effect` 的值还可以设置为 `NoExecute` ,下文会详细描述这个值。 * 如果未被过滤的 taint 中存在一个以上 effect 值为 `NoSchedule` 的 taint,则 Kubernetes 不会将 pod 分配到该节点。 -* 如果未被过滤的 taint 中不存在 effect 值为 `NoSchedule` 的 taint,但是存在 effect 值为 `PreferNoSchedule` 的 taint,则 Kubernetes 会*尝试*将 pod 分配到该节点。 +* 如果未被过滤的 taint 中不存在 effect 值为 `NoSchedule` 的 taint,但是存在 effect 值为 `PreferNoSchedule` 的 taint,则 Kubernetes 会 *尝试* 将 pod 分配到该节点。 * 如果未被过滤的 taint 中存在一个以上 effect 值为 `NoExecute` 的 taint,则 Kubernetes 不会将 pod 分配到该节点(如果 pod 还未在节点上运行),或者将 pod 从该节点驱逐(如果 pod 已经在节点上运行)。 -通过 taint 和 toleration ,可以灵活地让 pod *避开*某些节点或者将 pod 从某些节点驱逐。下面是几个使用例子: +通过 taint 和 toleration ,可以灵活地让 pod *避开* 某些节点或者将 pod 从某些节点驱逐。下面是几个使用例子: 前文我们提到过 taint 的 effect 值 `NoExecute` ,它会影响已经在节点上运行的 pod + * 如果 pod 不能忍受effect 值为 `NoExecute` 的 taint,那么 pod 将马上被驱逐 * 如果 pod 能够忍受effect 值为 `NoExecute` 的 taint,但是在 toleration 定义中没有指定 `tolerationSeconds`,则 pod 还会一直在这个节点上运行。 * 如果 pod 能够忍受effect 值为 `NoExecute` 的 taint,而且指定了 `tolerationSeconds`,则 pod 还能在这个节点上继续运行这个指定的时间长度。 @@ -350,7 +351,7 @@ behavior of pod evictions due to node problems, the system actually adds the tai in a rate-limited way. This prevents massive pod evictions in scenarios such as the master becoming partitioned from the nodes. --> -注意:为了保证由于节点问题引起的 pod 驱逐[rate limiting](/docs/concepts/architecture/nodes/)行为正常,系统实际上会以 rate-limited 的方式添加 taint。在像 master 和 node 通讯中断等场景下,这避免了 pod 被大量驱逐。 +为了保证由于节点问题引起的 pod 驱逐[rate limiting](/docs/concepts/architecture/nodes/)行为正常,系统实际上会以 rate-limited 的方式添加 taint。在像 master 和 node 通讯中断等场景下,这避免了 pod 被大量驱逐。 {{< /note >}} +### 标签页演示:内联 Markdown 和 HTML ```go-html-template {{}} {{% tab name="Markdown" %}} -This is **some markdown.** -{{< note >}}**Note:** It can even contain shortcodes.{{< /note >}} +这是 **一些 markdown 。** +{{< note >}}它甚至可以包含短代码。{{< /note >}} {{% /tab %}} {{< tab name="HTML" >}}
-

Plain HTML

-

This is some plain HTML.

+

纯 HTML

+

这是一些 HTML 。

{{< /tab >}} {{< /tabs */>}} @@ -223,13 +224,13 @@ This is **some markdown.** {{< tabs name="tab_with_md" >}} {{% tab name="Markdown" %}} -This is **some markdown.** -{{< note >}}**Note:** It can even contain shortcodes.{{< /note >}} +这是 **一些 markdown 。** +{{< note >}}它甚至可以包含短代码。{{< /note >}} {{% /tab %}} {{< tab name="HTML" >}}
-

Plain HTML

-

This is some plain HTML.

+

纯 HTML

+

这是一些 HTML 。

{{< /tab >}} {{< /tabs >}} From 044abec93e385ffa7dcb40a8f3a8eb70e4163e49 Mon Sep 17 00:00:00 2001 From: chentanjun <2799194073@qq.com> Date: Mon, 17 Feb 2020 13:13:28 +0800 Subject: [PATCH 039/111] update zh-trans content/zh/docs/concepts/policy/resource-quotas.md (#19037) --- .../docs/concepts/policy/resource-quotas.md | 851 ++++++++++++++++-- 1 file changed, 760 insertions(+), 91 deletions(-) diff --git a/content/zh/docs/concepts/policy/resource-quotas.md b/content/zh/docs/concepts/policy/resource-quotas.md index 08e6a07f83..1e00115344 100644 --- a/content/zh/docs/concepts/policy/resource-quotas.md +++ b/content/zh/docs/concepts/policy/resource-quotas.md @@ -4,115 +4,362 @@ approvers: title: 资源配额 --- -当多个用户或团队共享具有固定数目节点的集群时,人们会担心有人使用的资源超出应有的份额。 + +{{% capture overview %}} + + +当多个用户或团队共享具有固定节点数目的集群时,人们会担心有人使用超过其基于公平原则所分配到的资源量。 + + 资源配额是帮助管理员解决这一问题的工具。 -资源配额, 通过 `ResourceQuota` 对象来定义, 对每个namespace的资源消耗总量提供限制。 它可以按类型限制namespace下可以创建的对象的数量,也可以限制可被该项目以资源形式消耗的计算资源的总量。 +{{% /capture %}} + +{{% capture body %}} + + +资源配额,通过 `ResourceQuota` 对象来定义,对每个命名空间的资源消耗总量提供限制。它可以限制命名空间中某种类型的对象的总数目上限,也可以限制命令空间中的 Pod 可以使用的计算资源的总上限。 + + 资源配额的工作方式如下: -- 不同的团队在不同的namespace下工作。 目前这是自愿的, 但计划通过ACL (Access Control List 访问控制列表) - 使其变为强制性的。 -- 管理员为每个namespace创建一个或多个资源配额对象。 -- 用户在namespace下创建资源 (pods、 services等),同时配额系统会跟踪使用情况,来确保其不超过 - 资源配额中定义的硬性资源限额。 -- 如果资源的创建或更新违反了配额约束,则请求会失败,并返回 HTTP状态码 `403 FORBIDDEN` ,以及说明违反配额 - 约束的信息。 -- 如果namespace下的计算资源 (如 `cpu` 和 `memory`)的配额被启用,则用户必须为这些资源设定请求值(request) - 和约束值(limit),否则配额系统将拒绝Pod的创建。 - 提示: 可使用 LimitRange 准入控制器来为没有设置计算资源需求的Pod设置默认值。 - 作为示例,请参考 [演练](/docs/tasks/administer-cluster/quota-memory-cpu-namespace/) 来避免这个问题。 + +- 不同的团队可以在不同的命名空间下工作,目前这是非约束性的,在未来的版本中可能会通过 ACL (Access Control List 访问控制列表) 来实现强制性约束。 +- 集群管理员可以为每个命名空间创建一个或多个资源配额对象。 +- 当用户在命名空间下创建资源(如 Pod、Service 等)时,Kubernetes 的配额系统会跟踪集群的资源使用情况,以确保使用的资源用量不超过资源配额中定义的硬性资源限额。 +- 如果资源创建或者更新请求违反了配额约束,那么该请求会报错(HTTP 403 FORBIDDEN),并在消息中给出有可能违反的约束。 +- 如果命名空间下的计算资源 (如 `cpu` 和 `memory`)的配额被启用,则用户必须为这些资源设定请求值(request)和约束值(limit),否则配额系统将拒绝 Pod 的创建。 + 提示: 可使用 `LimitRanger` 准入控制器来为没有设置计算资源需求的 Pod 设置默认值。 + 若想避免这类问题,请参考[演练](/docs/tasks/administer-cluster/quota-memory-cpu-namespace/)中的示例。 -下面是使用namespace和配额构建策略的示例: + +下面是使用命名空间和配额构建策略的示例: -- 在具有 32 GiB 内存 和 16 核CPU资源的集群中, 允许A团队使用 20 GiB 内存 和 10 核的CPU资源, - 允许B团队使用 10GiB 内存和 4 核的CPU资源, 并且预留 2GiB 内存和 2 核的CPU资源供将来分配。 -- 限制 "testing" namespace使用 1 核CPU资源和 1GiB 内存。 允许 "production" namespace使用任意数量。 + +- 在具有 32 GiB 内存和 16 核 CPU 资源的集群中,允许 A 团队使用 20 GiB 内存 和 10 核的 CPU 资源,允许 B 团队使用 10 GiB 内存和 4 核的 CPU 资源,并且预留 2 GiB 内存和 2 核的 CPU 资源供将来分配。 +- 限制 "testing" 命名空间使用 1 核 CPU 资源和 1GiB 内存。允许 "production" 命名空间使用任意数量。 -在集群容量小于各namespace配额总和的情况下,可能存在资源竞争。 Kubernetes采用先到先服务的方式处理这类问题。 + +在集群容量小于各命名空间配额总和的情况下,可能存在资源竞争。资源竞争时,Kubernetes 系统会遵循先到先得的原则。 -无论是资源竞争还是配额的变更都不会影响已经创建的资源。 + +不管是资源竞争还是配额的修改,都不会影响已经创建的资源使用对象。 + ## 启用资源配额 -资源配额的支持在很多Kubernetes版本中是默认开启的。 当 apiserver 的 -`--admission-control=` 参数中包含 `ResourceQuota` 时,资源配额会被启用。 + +资源配额的支持在很多 Kubernetes 版本中是默认开启的。当 apiserver `--enable-admission-plugins=` 参数中包含 `ResourceQuota` 时,资源配额会被启用。 -当namespace中存在一个 `ResourceQuota` 对象时,该namespace即开始实施资源配额管理。 -一个namespace中最多只应存在一个 `ResourceQuota` 对象 + +当命名空间中存在一个 `ResourceQuota` 对象时,对于该命名空间而言,资源配额就是开启的。 + ## 计算资源配额 -用户可以对给定namespace下的 [计算资源](/docs/user-guide/compute-resources) 总量进行限制。 + +用户可以对给定命名空间下的可被请求的[计算资源](/docs/user-guide/compute-resources)总量进行限制。 + 配额机制所支持的资源类型: + | 资源名称 | 描述 | | --------------------- | ----------------------------------------------------------- | -| `cpu` | 所有非终止状态的Pod中,其CPU需求总量不能超过该值。 | -| `limits.cpu` | 所有非终止状态的Pod中,其CPU限额总量不能超过该值。 | -| `limits.memory` | 所有非终止状态的Pod中,其内存限额总量不能超过该值。 | -| `memory` | 所有非终止状态的Pod中,其内存需求总量不能超过该值。 | -| `requests.cpu` | 所有非终止状态的Pod中,其CPU需求总量不能超过该值。 | -| `requests.memory` | 所有非终止状态的Pod中,其内存需求总量不能超过该值。 | +| `limits.cpu` | 所有非终止状态的 Pod,其 CPU 限额总量不能超过该值。 | +| `limits.memory` | 所有非终止状态的 Pod,其内存限额总量不能超过该值。 | +| `requests.cpu` | 所有非终止状态的 Pod,其 CPU 需求总量不能超过该值。 | +| `requests.memory` | 所有非终止状态的 Pod,其内存需求总量不能超过该值。 | + +### 扩展资源的资源配额 + + +除上述资源外,在 Kubernetes 1.10 版本中,还添加了对[扩展资源](/docs/concepts/configuration/manage-compute-resources-container/#extended-resources)的支持。 + + +由于扩展资源不可超量分配,因此没有必要在配额中为同一扩展资源同时指定 `requests` 和 `limits`。对于扩展资源而言,目前仅允许使用前缀为 `requests.` 的配额项。 + + +以 GPU 拓展资源为例,如果资源名称为 `nvidia.com/gpu`,并且要将命名空间中请求的 GPU 资源总数限制为 4,则可以如下定义配额: + +* `requests.nvidia.com/gpu: 4` + + +有关更多详细信息,请参阅[查看和设置配额](#viewing-and-setting-quotas)。 + + ## 存储资源配额 -用户可以对给定namespace下的 [存储资源](/docs/user-guide/persistent-volumes) 总量进行限制。 + +用户可以对给定命名空间下的[存储资源](/docs/user-guide/persistent-volumes)总量进行限制。 + 此外,还可以根据相关的存储类(Storage Class)来限制存储资源的消耗。 + | 资源名称 | 描述 | | --------------------- | ----------------------------------------------------------- | -| `requests.storage` | 所有的PVC中,存储资源的需求不能超过该值。 | -| `persistentvolumeclaims` | namespace中所允许的 [PVC](/docs/user-guide/persistent-volumes/#persistentvolumeclaims) 总量。 | -| `.storageclass.storage.k8s.io/requests.storage` | 所有该storage-class-name相关的PVC中, 存储资源的需求不能超过该值。 | -| `.storageclass.storage.k8s.io/persistentvolumeclaims` | namespace中所允许的该storage-class-name相关的[PVC](/docs/user-guide/persistent-volumes/#persistentvolumeclaims)的总量。 | +| `requests.storage` | 所有 PVC,存储资源的需求总量不能超过该值。 | +| `persistentvolumeclaims` | 在该命名空间中所允许的 [PVC](/docs/user-guide/persistent-volumes/#persistentvolumeclaims) 总量。 | +| `.storageclass.storage.k8s.io/requests.storage` | 在所有与 storage-class-name 相关的持久卷声明中,存储请求的总和不能超过该值。 | +| `.storageclass.storage.k8s.io/persistentvolumeclaims` | 在与 storage-class-name 相关的所有持久卷声明中,命名空间中可以存在的[持久卷声明](/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims)总数。 | -例如,如果一个操作人员针对 "黄金" 存储类型与 "铜" 存储类型设置配额,操作员可以 -定义配额如下: + +例如,如果一个操作人员针对 `gold` 存储类型与 `bronze` 存储类型设置配额,操作人员可以定义如下配额: * `gold.storageclass.storage.k8s.io/requests.storage: 500Gi` * `bronze.storageclass.storage.k8s.io/requests.storage: 100Gi` + +在 Kubernetes 1.8 版本中,本地临时存储的配额支持已经是 Alpha 功能: + + +| 资源名称 | 描述 | +| ------------------------------- |----------------------------------------------------------- | +| `requests.ephemeral-storage` | 在命名空间的所有 Pod 中,本地临时存储请求的总和不能超过此值。 | +| `limits.ephemeral-storage` | 在命名空间的所有 Pod 中,本地临时存储限制值的总和不能超过此值。 | + + ## 对象数量配额 -给定类型的对象数量可以被限制。 支持以下类型: + +Kubernetes 1.9 版本增加了使用以下语法对所有标准的、命名空间域的资源类型进行配额设置的支持。 +* `count/.` + + +这是用户可能希望利用对象计数配额来管理的一组资源示例。 + +* `count/persistentvolumeclaims` +* `count/services` +* `count/secrets` +* `count/configmaps` +* `count/replicationcontrollers` +* `count/deployments.apps` +* `count/replicasets.apps` +* `count/statefulsets.apps` +* `count/jobs.batch` +* `count/cronjobs.batch` +* `count/deployments.extensions` + + +Kubernetes 1.15 版本增加了对使用相同语法来约束自定义资源的支持。 +例如,要对 `example.com` API 组中的自定义资源 `widgets` 设置配额,请使用 `count/widgets.example.com`。 + + + +当使用 `count/*` 资源配额时,如果对象存在于服务器存储中,则会根据配额管理资源。 +这些类型的配额有助于防止存储资源耗尽。例如,用户可能想根据服务器的存储能力来对服务器中 Secret 的数量进行配额限制。集群中存在过多的 Secret 实际上会导致服务器和控制器无法启动!用户可以选择对 Job 进行配额管理,以防止配置不当的 CronJob 在某命名空间中创建太多作业而导致集群拒绝服务。 + + + +在 Kubernetes 1.9 版本之前,可以在有限的一组资源上实施一般性的对象数量配额。 +此外,还可以进一步按资源的类型设置其配额。 + + +支持以下类型: + + | 资源名称 | 描述 | | ------------------------------- | ------------------------------------------------- | -| `configmaps` | namespace下允许存在的configmap的数量。 | -| `persistentvolumeclaims` | namespace下允许存在的[PVC](/docs/user-guide/persistent-volumes/#persistentvolumeclaims)的数量。 | -| `pods` | namespace下允许存在的非终止状态的pod数量。 如果pod 的 `status.phase 为 Failed 或 Succeeded` , 那么其处于终止状态。 | -| `replicationcontrollers` | namespace下允许存在的replication controllers的数量。 | -| `resourcequotas` | namespace下允许存在的 [resource quotas](/docs/admin/admission-controllers/#resourcequota) 的数量。 | -| `services` | namespace下允许存在的service的数量。 | -| `services.loadbalancers` | namespace下允许存在的load balancer类型的service的数量。 | -| `services.nodeports` | namespace下允许存在的node port类型的service的数量。 | -| `secrets` | namespace下允许存在的secret的数量。 | +| `configmaps` | 在该命名空间中允许存在的 ConfigMap 总数上限。 | +| `persistentvolumeclaims` | 在该命名空间中允许存在的 [PVC](/docs/user-guide/persistent-volumes/#persistentvolumeclaims) 的总数上限。 | +| `pods` | 在该命名空间中允许存在的非终止状态的 pod 总数上限。Pod 终止状态等价于 Pod 的 `.status.phase in (Failed, Succeeded)` = true | +| `replicationcontrollers` | 在该命名空间中允许存在的 RC 总数上限。 | +| `resourcequotas` | 在该命名空间中允许存在的[资源配额](/docs/admin/admission-controllers/#resourcequota)总数上限。 | +| `services` | 在该命名空间中允许存在的 Service 总数上限。 | +| `services.loadbalancers` | 在该命名空间中允许存在的 LoadBalancer 类型的服务总数上限。 | +| `services.nodeports` | 在该命名空间中允许存在的 NodePort 类型的服务总数上限。 | +| `secrets` | 在该命名空间中允许存在的 Secret 总数上限。 | -例如 `pods` 配额统计并保证单个namespace下创建 `pods` 的最大数量。 - -用户可能希望在namespace中为pod设置配额,来避免有用户创建很多小的pod,从而耗尽集群提供的pod IP地址。 + +例如,`pods` 配额统计某个命名空间中所创建的、非终止状态的 `Pod` 个数并确保其不超过某上限值。用户可能希望在某命名空间中设置 `pods` 配额,以避免有用户创建很多小的 Pod,从而耗尽集群所能提供的 Pod IP 地址。 + ## 配额作用域 -每个配额都有一组相关的作用域(scope),配额只会对作用域内的资源生效。 + +每个配额都有一组相关的作用域(scope),配额只会对作用域内的资源生效。配额机制仅统计所列举的作用域的交集中的资源用量。 + 当一个作用域被添加到配额中后,它会对作用域相关的资源数量作限制。 如配额中指定了允许(作用域)集合之外的资源,会导致验证错误。 -| 范围 | 描述 | + +| 作用域 | 描述 | +| ----- | ----------- | +| `Terminating` | 匹配所有 `spec.activeDeadlineSeconds` 不小于 0 的 Pod。 | +| `NotTerminating` | 匹配所有 `spec.activeDeadlineSeconds` 是 nil 的 Pod。 | +| `BestEffort` | 匹配所有 Qos 是 BestEffort 的 Pod。 | +| `NotBestEffort` | 匹配所有 Qos 不是 BestEffort 的 Pod。 | -`BestEffort` 作用域限制配额跟踪以下资源: `pods` + +`BestEffort` 作用域限制配额跟踪以下资源:`pods` -`Terminating`、 `NotTerminating` 和 `NotBestEffort` 限制配额跟踪以下资源: + +`Terminating`、`NotTerminating` 和 `NotBestEffort` 这三种作用域限制配额跟踪以下资源: * `cpu` * `limits.cpu` @@ -122,36 +369,285 @@ title: 资源配额 * `requests.cpu` * `requests.memory` -## 请求/约束 + +### 基于优先级类(PriorityClass)来设置资源配额 -分配计算资源时,每个容器可以为CPU或内存指定请求和约束。 -也可以设置两者中的任何一个。 +{{< feature-state for_k8s_version="1.12" state="beta" >}} -如果配额中指定了 `requests.cpu` 或 `requests.memory` 的值,那么它要求每个进来的容器针对这些资源有明确的请求。 如果配额中指定了 `limits.cpu` 或 `limits.memory`的值,那么它要求每个进来的容器针对这些资源指定明确的约束。 + +Pod 可以创建为特定的[优先级](/docs/concepts/configuration/pod-priority-preemption/#pod-priority)。 +通过使用配额规约中的 `scopeSelector` 字段,用户可以根据 Pod 的优先级控制其系统资源消耗。 -## 查看和设置配额 + +仅当配额规范中的 `scopeSelector` 字段选择到某 Pod 时,配额机制才会匹配和计量 Pod 的资源消耗。 + +本示例创建一个配额对象,并将其与具有特定优先级的 Pod 进行匹配。 +该示例的工作方式如下: + + +- 集群中的 Pod 可取三个优先级类之一,即 "low"、"medium"、"high"。 +- 为每个优先级创建一个配额对象。 + + +将以下 YAML 保存到文件 `quota.yml` 中。 + +```yaml +apiVersion: v1 +kind: List +items: +- apiVersion: v1 + kind: ResourceQuota + metadata: + name: pods-high + spec: + hard: + cpu: "1000" + memory: 200Gi + pods: "10" + scopeSelector: + matchExpressions: + - operator : In + scopeName: PriorityClass + values: ["high"] +- apiVersion: v1 + kind: ResourceQuota + metadata: + name: pods-medium + spec: + hard: + cpu: "10" + memory: 20Gi + pods: "10" + scopeSelector: + matchExpressions: + - operator : In + scopeName: PriorityClass + values: ["medium"] +- apiVersion: v1 + kind: ResourceQuota + metadata: + name: pods-low + spec: + hard: + cpu: "5" + memory: 10Gi + pods: "10" + scopeSelector: + matchExpressions: + - operator : In + scopeName: PriorityClass + values: ["low"] +``` + + +使用 `kubectl create` 命令运行以下操作。 + +```shell +kubectl create -f ./quota.yml +``` + +```shell +resourcequota/pods-high created +resourcequota/pods-medium created +resourcequota/pods-low created +``` + + +使用 `kubectl describe quota` 操作验证配额的 `Used` 值为 `0`。 + +```shell +kubectl describe quota +``` + +```shell +Name: pods-high +Namespace: default +Resource Used Hard +-------- ---- ---- +cpu 0 1k +memory 0 200Gi +pods 0 10 + + +Name: pods-low +Namespace: default +Resource Used Hard +-------- ---- ---- +cpu 0 5 +memory 0 10Gi +pods 0 10 + + +Name: pods-medium +Namespace: default +Resource Used Hard +-------- ---- ---- +cpu 0 10 +memory 0 20Gi +pods 0 10 +``` + + +创建优先级为 "high" 的 Pod。 +将以下 YAML 保存到文件 `high-priority-pod.yml` 中。 + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: high-priority +spec: + containers: + - name: high-priority + image: ubuntu + command: ["/bin/sh"] + args: ["-c", "while true; do echo hello; sleep 10;done"] + resources: + requests: + memory: "10Gi" + cpu: "500m" + limits: + memory: "10Gi" + cpu: "500m" + priorityClassName: high +``` + + +使用 `kubectl create` 运行以下操作。 + +```shell +kubectl create -f ./high-priority-pod.yml +``` + + +确认 "high" 优先级配额 `pods-high` 的 "Used" 统计信息已更改,并且其他两个配额未更改。 + +```shell +kubectl describe quota +``` + +```shell +Name: pods-high +Namespace: default +Resource Used Hard +-------- ---- ---- +cpu 500m 1k +memory 10Gi 200Gi +pods 1 10 + + +Name: pods-low +Namespace: default +Resource Used Hard +-------- ---- ---- +cpu 0 5 +memory 0 10Gi +pods 0 10 + + +Name: pods-medium +Namespace: default +Resource Used Hard +-------- ---- ---- +cpu 0 10 +memory 0 20Gi +pods 0 10 +``` + + +`scopeSelector` 在 `operator` 字段中支持以下值: + +* `In` +* `NotIn` +* `Exist` +* `DoesNotExist` + + +## 请求与限制 + + +分配计算资源时,每个容器可以为 CPU 或内存指定请求和约束。 +配额可以针对二者之一进行设置。 + + +如果配额中指定了 `requests.cpu` 或 `requests.memory` 的值,则它要求每个容器都显式给出对这些资源的请求。同理,如果配额中指定了 `limits.cpu` 或 `limits.memory` 的值,那么它要求每个容器都显式设定对应资源的限制。 + + +## 查看和设置配额 {#viewing-and-setting-quotas} + + Kubectl 支持创建、更新和查看配额: ```shell -$ kubectl create namespace myspace +kubectl create namespace myspace +``` -$ cat < compute-resources.yaml +```shell +cat < compute-resources.yaml apiVersion: v1 kind: ResourceQuota metadata: name: compute-resources spec: hard: - pods: "4" requests.cpu: "1" requests.memory: 1Gi limits.cpu: "2" limits.memory: 2Gi + requests.nvidia.com/gpu: 4 EOF -$ kubectl create -f ./compute-resources.yaml --namespace=myspace +``` -$ cat < object-counts.yaml +```shell +kubectl create -f ./compute-resources.yaml --namespace=myspace +``` + +```shell +cat < object-counts.yaml apiVersion: v1 kind: ResourceQuota metadata: @@ -160,61 +656,234 @@ spec: hard: configmaps: "10" persistentvolumeclaims: "4" + pods: "4" replicationcontrollers: "20" secrets: "10" services: "10" services.loadbalancers: "2" EOF -$ kubectl create -f ./object-counts.yaml --namespace=myspace +``` -$ kubectl get quota --namespace=myspace +```shell +kubectl create -f ./object-counts.yaml --namespace=myspace +``` + +```shell +kubectl get quota --namespace=myspace +``` + +```shell NAME AGE compute-resources 30s object-counts 32s +``` -$ kubectl describe quota compute-resources --namespace=myspace -Name: compute-resources -Namespace: myspace -Resource Used Hard --------- ---- ---- -limits.cpu 0 2 -limits.memory 0 2Gi -pods 0 4 -requests.cpu 0 1 -requests.memory 0 1Gi +```shell +kubectl describe quota compute-resources --namespace=myspace +``` -$ kubectl describe quota object-counts --namespace=myspace +```shell +Name: compute-resources +Namespace: myspace +Resource Used Hard +-------- ---- ---- +limits.cpu 0 2 +limits.memory 0 2Gi +requests.cpu 0 1 +requests.memory 0 1Gi +requests.nvidia.com/gpu 0 4 +``` + +```shell +kubectl describe quota object-counts --namespace=myspace +``` + +```shell Name: object-counts Namespace: myspace Resource Used Hard -------- ---- ---- configmaps 0 10 persistentvolumeclaims 0 4 +pods 0 4 replicationcontrollers 0 20 secrets 1 10 services 0 10 services.loadbalancers 0 2 ``` + +kubectl 还使用语法 `count/.` 支持所有标准的、命名空间域的资源的对象计数配额: + +```shell +kubectl create namespace myspace +``` + +```shell +kubectl create quota test --hard=count/deployments.extensions=2,count/replicasets.extensions=4,count/pods=3,count/secrets=4 --namespace=myspace +``` + +```shell +kubectl run nginx --image=nginx --replicas=2 --namespace=myspace +``` + +```shell +kubectl describe quota --namespace=myspace +``` + +```shell +Name: test +Namespace: myspace +Resource Used Hard +-------- ---- ---- +count/deployments.extensions 1 2 +count/pods 2 3 +count/replicasets.extensions 1 4 +count/secrets 1 4 +``` + + ## 配额和集群容量 -配额对象是独立于集群容量的。它们通过绝对的单位来表示。 所以,为集群添加节点, *不会* -自动赋予每个namespace消耗更多资源的能力。 + +资源配额与集群资源总量是完全独立的。它们通过绝对的单位来配置。所以,为集群添加节点时,资源配额*不会*自动赋予每个命名空间消耗更多资源的能力。 -有时可能需要更复杂的策略,比如: + +有时可能需要资源配额支持更复杂的策略,比如: + - 在几个团队中按比例划分总的集群资源。 - - 允许每个租户根据需要增加资源使用量,但要有足够的限制以防止意外资源耗尽。 - - 在namespace中添加节点、提高配额的额外需求。 + - 允许每个租户根据需要增加资源使用量,但要有足够的限制以防止资源意外耗尽。 + - 探测某个命名空间的需求,添加物理节点并扩大资源配额值。 -这些策略可以基于 ResourceQuota,通过编写一个检测配额使用,并根据其他信号调整各namespace下的配额硬性限制的 "控制器" 来实现。 + +这些策略可以通过将资源配额作为一个组成模块、手动编写一个控制器来监控资源使用情况,并结合其他信号调整命名空间上的硬性资源配额来实现。 -注意:资源配额对集群资源总体进行划分,但它对节点没有限制:来自多个namespace的Pod可能在同一节点上运行。 + +注意:资源配额对集群资源总体进行划分,但它对节点没有限制:来自不同命名空间的 Pod 可能在同一节点上运行。 + +## 默认情况下限制特定优先级的资源消耗 + + +有时候可能希望当且仅当某名字空间中存在匹配的配额对象时,才可以创建特定优先级(例如 "cluster-services")的 Pod。 + + +通过这种机制,操作人员能够将限制某些高优先级类仅出现在有限数量的命名空间中,而并非每个命名空间默认情况下都能够使用这些优先级类。 + + +要实现此目的,应使用 kube-apiserver 标志 `--admission-control-config-file` 传递如下配置文件的路径: + +{{< tabs name="example1" >}} +{{% tab name="apiserver.config.k8s.io/v1" %}} +```yaml +apiVersion: apiserver.config.k8s.io/v1 +kind: AdmissionConfiguration +plugins: +- name: "ResourceQuota" + configuration: + apiVersion: apiserver.config.k8s.io/v1 + kind: ResourceQuotaConfiguration + limitedResources: + - resource: pods + matchScopes: + - scopeName: PriorityClass + operator: In + values: ["cluster-services"] +``` +{{% /tab %}} +{{% tab name="apiserver.k8s.io/v1alpha1" %}} +```yaml +# 在 Kubernetes 1.17 中已不被推荐使用,请使用 apiserver.config.k8s.io/v1 +apiVersion: apiserver.k8s.io/v1alpha1 +kind: AdmissionConfiguration +plugins: +- name: "ResourceQuota" + configuration: + # 在 Kubernetes 1.17 中已不被推荐使用,请使用 apiserver.config.k8s.io/v1, ResourceQuotaConfiguration + apiVersion: resourcequota.admission.k8s.io/v1beta1 + kind: Configuration + limitedResources: + - resource: pods + matchScopes: + - scopeName: PriorityClass + operator: In + values: ["cluster-services"] +``` +{{% /tab %}} +{{< /tabs >}} + + +现在,仅当命名空间中存在匹配的 `scopeSelector` 的配额对象时,才允许使用 "cluster-services" Pod。 + + +示例: + +```yaml + scopeSelector: + matchExpressions: + - scopeName: PriorityClass + operator: In + values: ["cluster-services"] +``` + + +有关更多信息,请参见 [LimitedResources](https://github.com/kubernetes/kubernetes/pull/36765) 和[优先级类配额支持的设计文档](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/scheduling/pod-priority-resourcequota.md)。 + + ## 示例 -查看 [如何使用资源配额的详细示例](/docs/tasks/administer-cluster/quota-api-object/)。 + +查看[如何使用资源配额的详细示例](/docs/tasks/administer-cluster/quota-api-object/)。 -## 更多信息 +{{% /capture %}} -查看 [资源配额设计文档](https://git.k8s.io/community/contributors/design-proposals/resource-management/admission_control_resource_quota.md) 了解更多信息。 +{{% capture whatsnext %}} + + +查看[资源配额设计文档](https://git.k8s.io/community/contributors/design-proposals/resource-management/admission_control_resource_quota.md)了解更多信息。 + +{{% /capture %}} From 751cabbb73d11f9ecd84977274068cdaba7482d1 Mon Sep 17 00:00:00 2001 From: Kirk Larkin <6025110+serpent5@users.noreply.github.com> Date: Mon, 17 Feb 2020 10:05:28 +0000 Subject: [PATCH 040/111] A few tweaks to wording (#19136) Just a few tweaks where words were missing, etc. --- content/en/docs/concepts/architecture/nodes.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/content/en/docs/concepts/architecture/nodes.md b/content/en/docs/concepts/architecture/nodes.md index cb5b78d55e..0b740ad46c 100644 --- a/content/en/docs/concepts/architecture/nodes.md +++ b/content/en/docs/concepts/architecture/nodes.md @@ -30,7 +30,7 @@ A node's status contains the following information: * [Capacity and Allocatable](#capacity) * [Info](#info) -Node status and other details about a node can be displayed using below command: +Node status and other details about a node can be displayed using the following command: ```shell kubectl describe node ``` @@ -188,7 +188,7 @@ a Lease object. In Kubernetes 1.4, we updated the logic of the node controller to better handle cases when a large number of nodes have problems with reaching the master -(e.g. because the master has networking problem). Starting with 1.4, the node +(e.g. because the master has networking problems). Starting with 1.4, the node controller looks at the state of all nodes in the cluster when making a decision about pod eviction. @@ -212,9 +212,9 @@ there is only one availability zone (the whole cluster). A key reason for spreading your nodes across availability zones is so that the workload can be shifted to healthy zones when one entire zone goes down. -Therefore, if all nodes in a zone are unhealthy then node controller evicts at -the normal rate `--node-eviction-rate`. The corner case is when all zones are -completely unhealthy (i.e. there are no healthy nodes in the cluster). In such +Therefore, if all nodes in a zone are unhealthy then the node controller evicts at +the normal rate of `--node-eviction-rate`. The corner case is when all zones are +completely unhealthy (i.e. there are no healthy nodes in the cluster). In such a case, the node controller assumes that there's some problem with master connectivity and stops all evictions until some connectivity is restored. From f7c02fd4c953bc830a6d03c4da80bc1a4b4acba7 Mon Sep 17 00:00:00 2001 From: Zach Corleissen Date: Mon, 17 Feb 2020 02:19:28 -0800 Subject: [PATCH 041/111] Prune Bradamant3 from permissions (#19084) --- OWNERS_ALIASES | 3 --- 1 file changed, 3 deletions(-) diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES index 9a44dddfb3..bf898fed46 100644 --- a/OWNERS_ALIASES +++ b/OWNERS_ALIASES @@ -40,7 +40,6 @@ aliases: - mkorbi - rlenferink sig-docs-en-owners: # Admins for English content - - bradamant3 - bradtopol - daminisatya - gochist @@ -57,7 +56,6 @@ aliases: - zacharysarah - zparnold sig-docs-en-reviews: # PR reviews for English content - - bradamant3 - bradtopol - daminisatya - gochist @@ -159,7 +157,6 @@ aliases: - seokho-son - ysyukr sig-docs-maintainers: # Website maintainers - - bradamant3 - jimangel - kbarnard10 - pwittrock From bc6cb17bb739b6203217f96103afc331e695fd73 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Mon, 17 Feb 2020 18:47:29 +0300 Subject: [PATCH 042/111] Translate Start contributing page into Russian (#19124) --- content/ru/docs/contribute/start.md | 233 ++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100644 content/ru/docs/contribute/start.md diff --git a/content/ru/docs/contribute/start.md b/content/ru/docs/contribute/start.md new file mode 100644 index 0000000000..c6149d60a2 --- /dev/null +++ b/content/ru/docs/contribute/start.md @@ -0,0 +1,233 @@ +--- +title: Start contributing +slug: start +content_template: templates/concept +weight: 10 +card: + name: contribute + weight: 10 +--- + +{{% capture overview %}} + +Если вы хотите поучаствовать в работе над документацией Kubernetes, эта страница и связанные с ней темы могут помочь вам начать работу. Вам не нужно быть разработчиком или техническим писателем, чтобы внести вклад в документацию или улучшить сайт Kubernetes! Все, что вам нужно для тем на этой странице, это учетная запись на GitHub и браузер. + +Если вы ищете информацию про участие в репозиториях, связанным с кодом Kubernetes, обратитесь к [руководству сообщества Kubernetes](https://github.com/kubernetes/community/blob/master/governance.md). + +{{% /capture %}} + + +{{% capture body %}} + +## Основные сведения про документацию + +Документация Kubernetes написана на Markdown, обработана и развернута при помощи Hugo. Исходные файлы находятся на GitHub по адресу https://github.com/kubernetes/website. Основная часть документации хранится в директории `/content/en/docs/`. Часть справочной документации автоматически генерируется из скриптов в директории `update-imported-docs/`. + +Вы можете создавать новые задачи, редактировать содержимое и проверять изменения от других участников, — всё это доступно с сайта GitHub. Вы также можете использовать встроенный в GitHub поиск и историю коммитов. + +Не все задачи могут быть выполнены на GitHub, поэтому они обсуждаются в [intermediate](/docs/contribute/intermediate/) and +[advanced](/docs/contribute/advanced/) docs contribution guides. + +### Участие в документации SIG + +Документация Kubernetes поддерживается {{< glossary_tooltip text="специальной группой" term_id="sig" >}} (Special Interest Group, SIG) под названием SIG Docs. Мы [общаемся](#participate-in-sig-docs-discussions) с помощью канала Slack, списка рассылки и еженедельных видеозвонков. Будем рады новым участникам. Для получения дополнительной информации обратитесь к странице [Participating in SIG Docs](/docs/contribute/participating/). + +### Руководящие принципы по содержанию + +Сообщество SIG Docs разработало правила, которые касаются разрешенных видов контента в документации Kubernetes. Посмотрите [руководство по содержанию документации](/docs/contribute/style/content-guide/) для определения того, допустим ли контент, который вы хотите добавить. Задать вопросы про допустимый контент можно в Slack-канале [#sig-docs](#participate-in-sig-docs-discussions). + +### Правила оформления + +Мы поддерживаем [руководство по оформлению](/docs/contribute/style/style-guide/) с информацией о выборе, сделанном сообществом SIG Docs в отношении грамматики, синтаксиса, исходного форматирования и типографских соглашений. Прежде чем сделать свой первый вклад, просмотрите руководство по стилю и используйте его, когда у вас есть вопросы. + +SIG Docs совместными усилиями вносит изменения в руководство по оформлению. Чтобы предложить изменение или дополнение, добавьте его в повестку дня предстоящей встречи SIG Docs и посетите её, чтобы принять участие в обсуждении. Смотрите страницу с [продвинутым руководством](/docs/contribute/advanced/) для получения дополнительной информации. + +### Шаблоны страниц + +Мы используем шаблоны страниц, чтобы управлять представление наших страниц документации. Разберитесь как работают эти шаблоны, ознакомившись с разделом [Использование шаблонов страниц](/docs/contribute/style/page-templates/). + +### Макрокоды Hugo + +Документация Kubernetes с помощью Hugo конвертируется из формата разметки Markdown в HTML. Мы используем встроенные макрокоды Hugo, а также некоторые из своих собственных, созданных специально для документации Kubernetes. Посетите страницу [Нестандартные макрокоды Hugo](/docs/contribute/style/hugo-shortcodes/), чтобы узнать, как их использовать. + +### Мультиязычность + +Исходные файлы документации доступны на нескольких языках в директории `/content/`. Каждый язык имеет свою собственную директорию с двухбуквенным кодом, определенным стандартом[ISO 639-1 standard](https://www.loc.gov/standards/iso639-2/php/code_list.php). Например, исходники документации для английского языка хранится в директории `/content/en/docs/`. + +Более подробную информацию про участие в работе над документацией на нескольких языках ["Localize content"](/docs/contribute/intermediate#localize-content) в промежуточном руководстве по добавлению. + +Если вы заинтересованы в переводе документации на новый язык, посмотрите раздел ["Локализация"](/docs/contribute/localization/). + +## Создание хороших заявок + +Любой, у кого есть аккаунт на GitHub, может создать заявку (issue, или отчет об ошибке) в документации Kubernetes. Если вы заметили какую-либо какую-либо ошибку, даже если вы не знаете, как её исправить, [откройте ишью](#how-to-file-an-issue). Но не делайте этого, если нашли небольшую ошибку, например, опечатку, которую вы при желании можете исправить самостоятельно. В этом случае можете [исправить ее](#improve-existing-content) вместо того, чтобы писать об этом. + +### Как создать заявку + +- **Для существующей страницы** + + Если заметили проблему на существующей странице в [документации Kubernetes](/docs/), перейдите в конец страницы и нажмите кнопку **Create an Issue**. Если вы ещё не авторизованы в GitHub, сделайте это. После этого откроется страница с форма для создания нового запроса в GitHub с уже предварительно заполненным полями. + + При помощи разметки Markdown опишите как можно подробнее, что хотите. Там, где вы видите пустые квадратные скобки (`[ ]`), проставьте `x` между скобками. Если у вас есть предлагаемое решение проблемы, напишите его. + +- **Запросить новую страницу** + + Если вы хотите добавить что-то новое, но вы не уверены, на какую страницу документации это сделать или считаете, что новая информация не вписывается в существующие страницы, всё равно создайте ишью. Вы можете либо перейти на страницу документации, куда, по вашему мнению, нужно добавить новую информацию и создать заявку прямо с этой страницы, либо перейти по адресу [https://github.com/kubernetes/website/issues/new/](https://github.com/kubernetes/website/issues/new/) и написать что вы хотите там. + +### Как заполнить хорошую заявку + +Чтобы нам самим убедиться, что понимаем вас правильно, помните следующее: + +- Используйте шаблон ишью и заполните его как можно подробнее. +- Четко изложите суть вашего проблемы, как она сказывается на пользователях. +- Как можно меньше ограничьте охват изменений в вашей заявке. Задачи с большим объемом работы разбейте на более мелкие. + Например, "Fix the security docs" не является проблемой, требующей немедленного решения, зато заявка с заголовком "Add details to the 'Restricting network access' topic", вероятно, такой является. +- Если проблема связана с другой заявкой или пулреквестом, вы можете указать сослаться на них, либо по его полному URL-адресу, либо по их номеру с `#`. Например, `Introduced by #987654`. +- Будьте уважительны и избегайте жалоб. Например, заголовок ишью "The docs about X suck" явно не несёт ничего полезного или чтобы на него реагировали. + [Нормы поведения](/community/code-of-conduct/) также применяется к общению в GitHub-репозиториях Kubernetes. + +## Участие в дискуссиях SIG Docs + +Команда SIG Docs общается следующими способами: + +- [Зарегистрируйтесь в Slack-канале Kubernetes](http://slack.k8s.io/), а затем присоединитесь к каналу `#sig-docs`, где мы в режиме реального времени обсуждаем всё, что связано с документацией. И не забудьте представиться! +- [Подпишитесь на список рассылки `kubernetes-sig-docs`](https://groups.google.com/forum/#!forum/kubernetes-sig-docs), где проходят более общие дискуссии и принимаются официальные решения. +- Участвуйте в [еженедельной видеовстрече IG Docs](https://github.com/kubernetes/community/tree/master/sig-docs), которая анонсируется в Slack-канале и списке рассылки. В данный момент эти встречи проводятся в Zoom, поэтому вам необходимо загрузить клиент Zoom или позвонить по телефону. + +{{< note >}} +Вы всегда можете узнать когда будет очередное еженедельное собрание SIG Docs в [календаре собраний сообщества Kubernetes](https://calendar.google.com/calendar/embed?src=cgnt364vd8s86hr2phapfjc6uk%40group.calendar.google.com&ctz=America/Los_Angeles). +{{< /note >}} + +## Улучшение существующего текста + +Чтобы улучшить текущее содержимое документации, вам нужно открыть _пулреквест (pull request, PR)_ после того, как вы сделаете _копию (fork)_ оригинального репозитория. Эти два термина [относятся к GitHub](https://help.github.com/categories/collaborating-with-issues-and-pull-requests/). +Для начала работы, которая показана в этом разделе, вам не нужно знать всё про эти понятия, так как вы всё можете делать в своём браузере. Когда вы перейдете к продвинутому руководству участника документации, тогда вам понадобиться пополнить свои знания Git. + +Примечание. Разработчики кода Kubernetes. Если вы документируете новую функцию для предстоящего выпуска Kubernetes, ваш процесс будет немного другим. См. Документирование функции для руководства по процессу и информации о сроках. + +{{< note >}} +**Для разработчиков кода Kubernetes**: если вы документируете новую функциональность для новой версии Kubernetes, то процесс рассмотрения будет немного другим. Посетите страницу [Документирование функциональности](/docs/contribute/intermediate/#sig-members-documenting-new-features), чтобы узнать про процесс и информацию о крайних сроках. +{{< /note >}} + +### Подписание CLA-соглашения CNCF {#sign-the-cla} + +Прежде чем внести вклад в код или документацию Kubernetes, вам **обязательно** следует прочитать [руководство для участников](https://github.com/kubernetes/community/blob/master/contributors/guide/README.md) и [подписать лицензионное соглашение участника (Contributor License Agreement, CLA)](https://github.com/kubernetes/community/blob/master/CLA.md). +Не переживайте — подписание не займет много времени! + +### Поиск задач для работы + +Если вы уже нашли что исправить, просто следуйте инструкциям ниже. Для этого вам не обязательно [создавать ишью](#file-actionable-issues) (хотя вы, безусловно, пойти этим путём). + +Если вы хотите ещё не определились с тем, над чем хотите поработать, перейдите по адресу [https://github.com/kubernetes/website/issues](https://github.com/kubernetes/website/issues) и найдите ишью с меткой `good first issue` (вы можете использовать [эту](https://github.com/kubernetes/website/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) ссылку для быстрого поиска). Прочитайте комментарии, чтобы убедиться что нет открытого пулреквеста для решения текущей ишью, а также, что никто другой не оставил комментарий, что он работает над этой задачей в последнее время (как правило, 3 дня). Добавьте комментарий, что вы хотели бы заняться решением этой задачи. + +### Выбор правильной ветки в Git + +Самым важный момент в создании пулреквестов — это выбор нужной ветки для вашей работы. Используйте эти рекомендации, чтобы принять верное решение: + +- Используйте ветку `master` для исправления ошибок в текущей документации, либо чтобы улучшить существующий текст. +- Используйте ветку `master` для документирования функциональности в текущей версии Kubernetes, для которой отсутствовала документация. Прежде всего вам нужно написать документацию на английском языке, а затем команды по переводам подхватят это изменение, чтобы актуализировать перевод. +- Если вы работаете над переводом, вам нужно следовать соглашению в этой конкретной локализации. Чтобы понять это, вы можете другие пулреквесты (подсказка: `is:pr is:merged label:language/xx`) + {{< comment >}}Localization note: when localizing that tip, replace `xx` + with the actual ISO3166 two-letter code for your target locale.{{< /comment >}} + - Некоторые команды локализации работают с пулреквестами, которые ориентированы на ветку `master` + - Другие команды локализации работают с рядом долговечных веток, периодически сливая их в ветку `master`. Такая ветка именуется как dev-\-\.\, например, `dev-{{< release-branch >}}-ja.1`. +- Если вы пишете или обновляете документацию к выпуску грядущего изменения, то вам необходимо знать мажорную и минорную версию Kubernetes, в которой это изменение впервые появится. + - Например, если переключатель возможностей (feature gates) JustAnExample должен измениться с альфа-версии на бета-версию в следующей минорной версии, вам необходимо знать номер этой версии. + - Найдите ветку выпуска, названную для этой версии. Например, функциональность, которая изменились в выпуске v{{< release-branch >}}, будет документирована в ветке `dev-{{< release-branch >}}`. + +Если вы все еще не уверены, какую ветку выбрать, спросите в Slack-канале `#sig-docs` или посетите еженедельную встречу SIG Docs, чтобы внести ясность. + +### Отправка пулреквеста + +Следуйте описанным ниже шагам, чтобы создать пулреквест для улучшения документации Kubernetes. + +1. На странице, которую вы хотите отредактировать, щелкните на иконку карандаша в правом верхнем углу. Откроется новая страница на GitHub с небольшой подсказкой. +2. Если вы ранее не делали копию репозитория документации Kubernetes, вам будет предложено это сделать. Создайте копию репозитория под своим логином GitHub, а не в организации, в которой вы состоите. URL-адрес копии репозитория будет выглядит как `https://github.com//website`, в случае у вас нет репозитория с таким же названием. + + Поскольку у вас нет доступа к оригинальному репозиторию и соответственно вы не можете отправлять напрямую изменения в основную ветку, вам нужно сделать копию репозитория Kubernetes. + +3. Откроется редактор GitHub для редактирования исходного файла в формате Markdown. Внесите свои изменения. Под редактором заполните форму **Propose file change**. Первое поле — краткое содержание вашего сообщения коммита, оно должно содержать не более 50 символов. Второе поле является необязательным, в нём вы можете подробно расписать суть ваших изменений. + + {{< note >}} + Не ссылайте на другие ишью или пулреквесты на GitHub в сообщении коммита. Вы можете сослаться на них в тексте пулреквеста. +{{< /note >}} + + Нажмите на кнопку **Propose file change**. Изменения в файле записываются в виде коммита в новой ветке вашей копии репозитория, которая автоматически будет иметь имя что-то вроде `patch-1`. + +4. На следующей странице вам будут показаны различия в вашей ветке (поля выбора **head fork** и **compare**) с текущим состоянием **оригинального репозитория (base fork)** в **основной ветке (base)** (по умолчанию ветка `master` в репозитории `kubernetes/website`). Вы можете выбрать другое значение в полях выбора, но не делайте этого сейчас. Сравните различия и если всё верно, нажмите кнопку **Create pull request**. + + {{< note >}} + Если вы не хотите создавать пулреквест в данный момент, это можно сделать позже, если перейти на страницу репозитория сайта Kubernetes или вашей копии репозитория. На сайте GitHub вам предложит открыть пулреквест, если он обнаружит новую ветку в вашей копии репозитория. +{{< /note >}} + +5. Отобразится форма с заголовком **Open a pull request**. Название пулреквеста будет содержать краткое описание из сообщения коммита, хотя вы можете изменить его при необходимости. В описании пулреквеста будет остальная информация из сообщения коммита (если оно есть) и небольшой шаблон с текстом. Прочитайте текст шаблона и сделайте то, что там описано, а затем удалите этот шаблонный текст. Если вы добавите в описание пулреквест `fixes #<000000>` или `closes #<000000>`, где `#<000000>` - номер связанной заявки, то GitHub автоматически закроет указанную заявку при слиянии пулреквеста. Оставьте флажок **Allow edits from maintainers** отмеченным. Нажмите на кнопку **Create pull request**. + + Поздравляем! Ваш пулреквест добавлен в список [пулреквестов](https://github.com/kubernetes/website/pulls). + + Через несколько минут вы сможете просмотреть версию сайта с изменениями в вашем пулреквесте. Перейдите в низ страницы пулреквеста на вкладке **Conversation** и там нажмите на ссылку **Details** рядом с проверкой `deploy/netlify`. По умолчанию она откроется в текущей вкладке. + + {{< note >}} + Пожалуйста, открывайте пулреквест, изменения которого затрагивают только один язык. Например, если вам нужно одинаково изменить один и тот же пример кода в нескольких языках, откройте по отдельному пулреквесту для каждого языка. + {{< /note >}} + +6. Ожидайте, когда проверят ваш пулреквест. Как правило, рецензенты выбираются авматоматически ботом `k8s-ci-robot`. Если рецензент попросил изменить пулреквест, вы можете сделать это, если перейдёте на вкладку **Files changed** и щёлкните на иконку с карандашом на любом изменённом файле в вашем пулреквесте. Сохранение измененного файла оформляется в виде нового коммита в ветке, указанной в пулреквесте. Если вы ожидаете новую проверку изменений от рецензента, заранее попросите его об этом не более одного раза в 7 дней. Вы также можете зайти в Slack-канал #sig-docs — это хорошее место, где можно попросить проверку пулреквеста. + +7. Если ваши изменения одобрены, то рецензент объединяет соответствующий пулреквест. Через несколько минут вы сможете сможете увидеть его в действии на сайте Kubernetes. + +Это только один из способов отправить пулреквест. Если вы уже опытный пользователь Git и GitHub, вы можете вносить изменения, используя локальный GUI-клиент или Git из терминала вместо того, чтобы использовать интерфейс GitHub для этого. Некоторые основы использования Git-клиента из командной строки обсуждаются в [продвинутом](/docs/contribute/intermediate/) руководстве участника. + +## Просмотр пулреквестов в документацию + +Новички документации могут обозревать пулреквесты. Вы можете изучить кодовую базу и завоевать доверие к себе со стороны коллег-участников. Документация на английском — это первоисточник содержимого. Мы общаемся на английском языке во время еженедельных встреч и в объявлениях сообщества. Владение английским языком может быть разным, поэтому используйте простой и прямой язык в своих обзорах пулреквестов. Полезные обзоры фокусируются как на мелких деталях, так и на потенциальном влиянии изменений. + +Обзоры не носят «обязательный характер», это означает, что только ваша проверка не приведет к слиянию пулреквеста. Тем не менее, это не делает ваши обзоры бесполезными. Даже только просмотр изменений в пулреквеста поможет вам понять как происходит рабочий процесс, какие могут быть трудности и проблемы. Перед проверкой пулреквестов ознакомьтесь с [руководством по содержанию](/docs/contribute/style/content-guide/) и [руководством по оформлению](/docs/contribute/style/style-guide/), чтобы узнать, каким должен быть содержимое и как оно должно быть оформлено.. + +### Рекомендации + +- Будьте вежливы, внимательны и помогайте другим +- Не забывайте отмечать также положительные стороны пулреквеста +- Будьте чутким и думайте, как ваши комментарии могут быть восприняты +- Проявите добрые намерения и задавайте уточняющие вопросы +- Опытным участникам: помогайте новым участникам, их работа требует глаз да глаз + +### Поиск и проверка пулреквеста + +1. Перейдите по URL-адресу [https://github.com/kubernetes/website/pulls](https://github.com/kubernetes/website/pulls). Вы увидите список всех пулреквестов в репозиторий сайта Kubernetes и его документации. + +2. По умолчанию открываются открытые пулреквесты (статус `open`), поэтому вы не увидите закрытых или принятых пулреквестов. Рекомендуется добавить дополнительный фильтр `cncf-cla: yes`, а также для вашей первой проверки пулреквеста неплохо применить ещё и `size/S` и `size/XS`. Метка с размером назначается автоматически в зависимости от количества изменённых строк кода в пулреквесте. Вы можете применить фильтры, используя поля выбора в верхней части страницы, либо воспользоваться [этой ссылкой](https://github.com/kubernetes/website/pulls?q=is%3Aopen+is%3Apr+label%3A%22cncf-cla%3A+yes%22+label%3Asize%2FS) для просмотра небольших пулреквестов. Все фильтры объединены в логическое `AND`, поэтому у вас не получиться искать по меткам `size/XS` и `size/S` одновременно. + +3. Перейдите на вкладку **Files changed**. Посмотрите изменения, внесенные в PR, а также изучите любые связанные задачи (если есть). Если вы видите ошибку, неточность или хотите внести улучшение, то наведите курсор на строку и щелкните на появившийся символ `+`. + + Вы можете написать комментарий, после чего нажать на кнопку **Add single comment** или **Start a review**. Как правило, лучше начать проверку (review), поскольку тогда вы сможете оставить несколько комментариев и уведомить автора PR только после завершения рецензирования, вместо того, чтобы упоминать его в каждом комментарии. + +4. После окончания разбора пулреквеста, нажмите на кнопку **Review changes** вверху страницы. Вы можете подвести краткий итог своей проверки и выполнить одно из действий: просто прокомментировать, одобрить или запросить изменения. Новым участникам нужно всегда только комментировать (кнопка **Comment**) пулреквесты. + + +Спасибо за обзор пулреквеста! Если вы новенький в проекте, рекомендуется попросить кого-нибудь оценить ваш обзор пулреквеста. Slack-канал `#sig-docs` — отличное место для этого. + +## Написание постов в блоге + +Любой может написать пост в блоге и отправить его на рассмотрение. Посты блога не должны носит коммерческий характер и должны отражать опыт, который может широко применён в сообществе Kubernetes. + +Чтобы заявить о посте вы можете отправить его, используя [форму блога Kubernetes](https://docs.google.com/forms/d/e/1FAIpQLSdMpMoSIrhte5omZbTE7nB84qcGBy8XnnXhDFoW0h7p2zwXrw/viewform), либо же выполнить следующие действия. + +1. [Подпишите CLA](#sign-the-cla), если вы еще этого не сделали. +2. Изучите разметку Markdown у текущих постов блога в репозитории сайта. +3. Напишите свою статью в вашем любимом текстовом редакторе. +4. По ссылке из второго шага нажмите на кнопку **Create new file**. Скопируйте из своего редактора текст и вставьте в многострочное поле. Назовите файл так, чтобы он соответствовал предлагаемому заголовку статьи в блоге, но не указывайте дату в имени файла. Рецензенты блога будут работать с вами над окончательным именем файла и датой публикации записи. +5. Когда вы сохраните файл, начнётся описанный выше процесс принятия пулреквеста в GitHub. +6. Рецензент блога рассмотрит вашу статью и вместе с вами будет работать над ее улучшением. Когда запись в блоге будет одобрена, будет известна дата публикации вашей статьи. + +## Отправка примеров использования + +В примерах использования показывается, как организации используют Kubernetes для решения собственных реальных проблем. Они написаны в сотрудничестве с маркетинговой командой Kubernetes, которой занимается {{< glossary_tooltip text="CNCF" term_id="cncf" >}}. + +Ознакомьтесь с [существующими примерами использования](https://github.com/kubernetes/website/tree/master/content/en/case-studies). Воспользуйтесь [формой добавления нового примера использования Kubernetes](https://www.cncf.io/people/end-user-community/), чтобы поделиться своим опытом. + +{{% /capture %}} + +{{% capture whatsnext %}} + +Если вы хорошо поняли темы, затронутые в этом разделе, но хотите глубже взаимодействовать с командой документации Kubernetes, прочитайте [расширенное руководство по участию в документации](/docs/contribute/intermediate/). + +{{% /capture %}} From b47c665674860a26b37b3f406b1a707477556c85 Mon Sep 17 00:00:00 2001 From: Jie Shen Date: Tue, 18 Feb 2020 00:13:30 +0800 Subject: [PATCH 043/111] Upgrade command of homebrew installs minikube (#18281) --- content/de/docs/tasks/tools/install-minikube.md | 2 +- content/es/docs/tasks/tools/install-minikube.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/content/de/docs/tasks/tools/install-minikube.md b/content/de/docs/tasks/tools/install-minikube.md index e305b2ec05..c3d08bac30 100644 --- a/content/de/docs/tasks/tools/install-minikube.md +++ b/content/de/docs/tasks/tools/install-minikube.md @@ -49,7 +49,7 @@ Minikube unterstützt auch die Option `--vm-driver=none`, mit der die Kubernetes Die einfachste Möglichkeit, Minikube unter macOS zu installieren, ist die Verwendung von [Homebrew](https://brew.sh): ```shell -brew cask install minikube +brew install minikube ``` Sie können es auch auf macOS installieren, indem Sie eine statische Binärdatei herunterladen: diff --git a/content/es/docs/tasks/tools/install-minikube.md b/content/es/docs/tasks/tools/install-minikube.md index de99085d50..7538afa704 100644 --- a/content/es/docs/tasks/tools/install-minikube.md +++ b/content/es/docs/tasks/tools/install-minikube.md @@ -49,7 +49,7 @@ Minikube también soporta una opción `--vm-driver=none` que ejecuta los compone La forma más fácil de instalar Minikube en macOS es usar [Homebrew](https://brew.sh): ```shell -brew cask install minikube +brew install minikube ``` También puedes instalarlo en macOS descargando un ejecutable autocontenido: From 403c6d059d02d74c75f625226b5c37307bb68a8e Mon Sep 17 00:00:00 2001 From: Felix Geelhaar Date: Mon, 17 Feb 2020 17:15:29 +0100 Subject: [PATCH 044/111] Update installation of minikube on macOS (#19143) Installation through brew cask install minikube is no longer supported, as there is not such a binary. Corrected to brew install minikube works. From e836c83b4a8876305d4064b70a277deb9d19904c Mon Sep 17 00:00:00 2001 From: Tim Bannister Date: Mon, 17 Feb 2020 18:21:29 +0000 Subject: [PATCH 045/111] =?UTF-8?q?Tidy=20=E2=80=9CParticipating=20in=20SI?= =?UTF-8?q?G=20Docs=E2=80=9D=20(#19151)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix broken link - Move localization work from Reviewers group to Anyone - Minor other tidying --- content/en/docs/contribute/participating.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/content/en/docs/contribute/participating.md b/content/en/docs/contribute/participating.md index b63c33e915..dbc44b5867 100644 --- a/content/en/docs/contribute/participating.md +++ b/content/en/docs/contribute/participating.md @@ -24,6 +24,7 @@ You can also become a [member](#members), access and entail certain responsibilities for approving and committing changes. See [community-membership](https://github.com/kubernetes/community/blob/master/community-membership.md) for more information on how membership works within the Kubernetes community. + The rest of this document outlines some unique ways these roles function within SIG Docs, which is responsible for maintaining one of the most public-facing aspects of Kubernetes -- the Kubernetes website and documentation. @@ -52,7 +53,8 @@ aspects of Kubernetes -- the Kubernetes website and documentation. Anyone can do the following: - Open a GitHub issue against any part of Kubernetes, including documentation. -- Provide non-binding feedback on a pull request/ +- Provide non-binding feedback on a pull request. +- Help to localize existing content - Bring up ideas for improvement on [Slack](http://slack.k8s.io/) or the [SIG docs mailing list](https://groups.google.com/forum/#!forum/kubernetes-sig-docs). - Use the `/lgtm` Prow command (short for "looks good to me") to recommend the changes in a pull request for merging. {{< note >}} @@ -120,7 +122,6 @@ changes. Reviewers can: - Triage and categorize issues - Review pull requests and provide binding feedback - Create diagrams, graphics assets, and embeddable screencasts and videos -- Localization - Edit user-facing strings in code - Improve code comments @@ -166,7 +167,7 @@ add new members to a GitHub group. Approvers are members of the [@kubernetes/sig-docs-maintainers](https://github.com/orgs/kubernetes/teams/sig-docs-maintainers) -GitHub group. See [Teams and groups within SIG Docs](#teams-and-groups-within-sig-docs). +GitHub group. See [SIG Docs teams and automation](#sig-docs-teams-and-automation) for details. Approvers can do the following: From c2cc1a1c87dae46411b827da8a22ee687efb05b0 Mon Sep 17 00:00:00 2001 From: Eko Simanjuntak Date: Tue, 18 Feb 2020 09:19:28 +0700 Subject: [PATCH 046/111] Change Kontainer to Node (#19105) --- content/id/docs/concepts/configuration/assign-pod-node.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/id/docs/concepts/configuration/assign-pod-node.md b/content/id/docs/concepts/configuration/assign-pod-node.md index f78bc54b48..12cf9433d6 100644 --- a/content/id/docs/concepts/configuration/assign-pod-node.md +++ b/content/id/docs/concepts/configuration/assign-pod-node.md @@ -1,5 +1,5 @@ --- -title: Menetapkan Pod ke Kontainer +title: Menetapkan Pod ke Node content_template: templates/concept weight: 30 --- From 6b4712e47d81a53caddf8428c9e0c781f0fc0e02 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Tue, 18 Feb 2020 09:07:28 +0300 Subject: [PATCH 047/111] Translate Participating in SIG Docs page into Russian (#19150) * Translate Participating in SIG Docs page into Russian * Fixes --- content/ru/docs/contribute/participating.md | 208 ++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 content/ru/docs/contribute/participating.md diff --git a/content/ru/docs/contribute/participating.md b/content/ru/docs/contribute/participating.md new file mode 100644 index 0000000000..2460e19d6d --- /dev/null +++ b/content/ru/docs/contribute/participating.md @@ -0,0 +1,208 @@ +--- +title: Участие в SIG Docs +content_template: templates/concept +card: + name: contribute + weight: 40 +--- + +{{% capture overview %}} + +SIG Docs — это одна из [специальных групп](https://github.com/kubernetes/community/blob/master/sig-list.md) в проекте Kubernetes, которая занимается написанием, обновлением и поддержкой документации Kubernetes в целом. Перейдите на страницу про [SIG Docs в GitHub-репозитории](https://github.com/kubernetes/community/tree/master/sig-docs), чтобы узнать подробную информацию об этой группе. + +SIG Docs активно принимает правки и дополнения в документацию, так и отзывы от всех участников. Любой может открыть пулреквест (PR), либо сообщить про ошибки в тексте или просто прокомментировать выполняемые пулреквесты. + +Вы также можете стать [членом](#члены), [рецензентом](#рецензенты) или [утверждающим](#утверждающие). Эти роли расширяют ваши возможности, но и предлагают выполнение определенных обязанностей по рассмотрению и принятию изменений. Изучите содержимого файла [community-membership](https://github.com/kubernetes/community/blob/master/community-membership.md) в директории сообщества репозитория, чтобы узнать про членство в сообществе Kubernetes. В остальной части этой страницы кратко рассматривается функционирование ролей в группе SIG Docs, которая в совокупности отвечает за поддержание одного из самой публичной части Kubernetes — сайта и документации Kubernetes. + +{{% /capture %}} + +{{% capture body %}} + +## Роли и обязанности + +- **Любой** может поучаствовать в документацию Kubernetes. Для этого вам нужно только [подписать CLA](/docs/contribute/start#sign-the-cla) и иметь аккаунт на GitHub. +- **Члены** организации Kubernetes — участники, которые активно занимаются пректом Kubernetes, как правило, открывая пулреквесты с принятыми изменениями. Посмотрите файл [Членство в сообществе](https://github.com/kubernetes/community/blob/master/community-membership.md), чтобы узнать про необходимые условия для членства. +- **Рецензент** SIG Docs — член организации Kubernetes, который занимается проверкой пулреквестов и поэтому был добавлен в соответствующую группу на GitHub и в файлы `OWNERS` в GitHub-репозитории. +- **Утверждающий** SIG Docs — член организации с хорошей репутацией, который подтвердил неизменную приверженность проекту. Утверждающий может принимать пулреквесты и публиковаться от имени организации Kubernetes. Утверждающие также могут представлять группу SIG Docs в более крупном сообществе Kubernetes. Некоторые из задач утверждающего SIG Docs, например, координация новой версии, требуют значительных затрат по времени. + +## Любой + +Кто угодно может сделать следующее: + +- Открыть ишью на GitHub в любую часть Kubernetes, включая документацию. +- Дать рекомендацию или предложить улучшение в пулреквесте. +- Предложить идею по улучшению в Slack](http://slack.k8s.io/) или в [список рассылки SIG Docs](https://groups.google.com/forum/#!forum/kubernetes-sig-docs). +- Использовать команду `/lgtm` (сокращение от "looks good to me") бота Prow, чтобы одобрить изменения в пулреквесте. + {{< note >}} + Если вы не входите в организацию Kubernetes, то команда `/lgtm` не проставил автоматически соответствующую метку. + {{< /note >}} + +После [подписания CLA](/docs/contribute/start#sign-the-cla) каждый также может: +- Открыть пулреквест, чтобы улучшить существующий текст, либо что-то новое, или написать запись в блоге или описать пример использования. + +## Члены + +Члены — это участники проекта Kubernetes, которые удовлетворяют [критериям членства](https://github.com/kubernetes/community/blob/master/community-membership.md#member). SIG Docs ценит участие всех членов сообщества Kubernetes и часто просит дать обратную связь от членов других SIG-групп для соблюдения технической точности. + +Любой член [организации Kubernetes](https://github.com/kubernetes) может сделать следующее: + +- Всё то же самое, что и [любой другой участник](#любой) +- Использовать команду `/lgtm` в комментарии для автоматического добавления метки LGTM (looks good to me) для пулреквеста. +- Использовать команду `/hold` в комментарии для блокировки слияния пулреквеста, если он имеет метку LGTM и другие утверждающие метки. +- Использовать команду `/assign` в комментарии, чтобы назначить рецензента, который будет проверят пулреквест. + +### Членство + +После того, как вы успешно отправили не менее 5 содержательных пулреквестов, вы можете стать [членом](https://github.com/kubernetes/community/blob/master/community-membership.md#member) организации Kubernetes. Следуйте нижеперечисленным шагам: + +1. Найдите двух рецензентов или утверждающих, которые [поддержат](/docs/contribute/advanced#sponsor-a-new-contributor) ваше членство. + + Запросите спонсорство в канале [#sig-docs Kubernetes Slack](https://kubernetes.slack.com) или в [списке рассылки SIG Docs](https://groups.google.com/forum/#!forum/kubernetes-sig-docs). + + {{< note >}} + Не отправляйте электронное письмо и не пишите личное сообщение в Slack кому-либо из участников SIG Docs. + {{< /note >}} + +2. Создайте ишью в репозитории `kubernetes/org`, чтобы запросить членство. + Заполните шаблон, предварительно изучив правила [членства в сообществе](https://github.com/kubernetes/community/blob/master/community-membership.md). + +3. Сообщите вашим спонсорам про вашу заявку на GitHub, упомянув их в ней на GitHub (добавив комментарий в форме `@`), либо отправив им ссылку напрямую, чтобы они могли добавить проголосовать ( `+1`). + +4. Когда ваше членство будет одобрено, член административной команды на GitHub, назначенный для обработки вашего пулреквеста, обновит ишью на GitHub, чтобы показать одобрение, а затем закроет проблему GitHub. + Поздравляем, теперь вы член организации! + +Если ваша заявка на членство не была одобрена, членский комитет даст уточнения или перечислит шаги, которые необходимо выполнить, прежде чем снова подать заявку. + +## Рецензенты + +Рецензенты — это члены GitHub-группы [@kubernetes/sig-docs-pr-reviews](https://github.com/orgs/kubernetes/teams/sig-docs-pr-reviews). Рецензенты проверяют пулреквесты документации и оставлять обратную связь по предлагаемым изменениях. Рецензенты могут: + +- Делать всё то, что и [любой участник](#любой) и [члены](#члены) +- Писать документацию для новой функциональности +- Назначать метки и классифицировать ишью +- Проверять пулреквесты и оставлять обязательные для выполнения рекомендации +- Создавайте диаграммы, графику и встраиваемые скринкасты и видеоролики +- Заниматься локализацией +- Редактировать строки в коде, относящиеся к интерфейсу пользователя +- Улучшать комментарии к коду + +### Выбор рецензентов для проверки пулреквестов + +Процесс выбора рецензентов для проверки пулреквестов автоматизирован. Вы можете попросить проверку у определенного рецензента, написав комментарий в пулреквесте: `/assign [@_github_handle]`. Чтобы показать, что пулреквест является правильным с технической точки зрения и не требует дополнительных изменений, рецензент добавляет комментарий с командой `/lgtm`. + +Если назначенный рецензент еще не просмотрел содержимое пулреквеста, может присоединиться другой проверяющий. Кроме того, вы можете назначить технических рецензентов и подождать их одобрение через комментарий с `/lgtm`. + +Также для совсем небольшого изменения, или такого, которое не требует технического рассмотрения, [утверждающие](#утверждающие) SIG Docs одобрить его через комментарий с `/lgtm`. + +Комментарий с `/approve` от рецензента игнорируется ботом и поэтому соответствующая метка не добавится к пулреквесту. + +### Как стать рецензентом + +Если вы соответствуете [требованием](https://github.com/kubernetes/community/blob/master/community-membership.md#reviewer), то можете стать рецензентом SIG Docs. Рецензенты в других SIG-группах должны подать новую заявку для получения статуса рецензента в SIG Docs. + +Для отправки заявки откройте пулреквест с добавлением самого себя в секцию `reviewers` [корневого файла OWNERS](https://github.com/kubernetes/website/blob/master/OWNERS) в репозитории `kubernetes/website`. Запросите проверку вашего пулреквеста одному или нескольким текущим утверждающим в группе SIG Docs. + +Если ваш пулреквест одобрен, вы становитесь рецензентом SIG Docs. Теперь бот [K8s-ci-robot](https://github.com/kubernetes/test-infra/tree/master/prow#bots-home) будет назначать и предлагать вас в качестве рецензента для проверки новых пулреквестов. + +После того, как ваша кандидатура будет одобрена, попросите текущего утверждающего SIG Docs добавить вас в GitHub-группу [@kubernetes/sig-docs-pr-reviews](https://github.com/orgs/kubernetes/teams/sig-docs-pr-reviews). Только члены GitHub-группы `kubernetes-website-admins` могут добавлять новых членов в какую-либо другую группу. + +## Утверждающие + +Утверждающие — члены GitHub-группы [@kubernetes/sig-docs-maintainers](https://github.com/orgs/kubernetes/teams/sig-docs-maintainers). Перейдите в раздел [Команды и группы в SIG Docs](#teams-and-groups-within-sig-docs) для получения дополнительной информации. + +Утверждающие могут делать следующее: + +- Все то же, что и [обычные участники](#любой), [члены](#члены) и [рецензенты](#рецензенты) +- Публиковать изменения от других участников путём одобрения и слияния пулреквестов с помощью комментария с командой `/approve`. + Если кто-то оставляет комментарий, не являясь при этом официальным рецензентом, бот проигнорирует такой одобряющий комментарий. +- Примите участие в работе команды выпуска новых версий Kubernetes как представитель документации +- Предлагать улучшения в руководстве по оформлению +- Предлагать улучшения для тестов документации +- Предлагать улучшения для сайта Kubernetes или других инструментов + +Если у PR есть метка `/lgtm`, или если утверждающий оставляет комментарий с командной с `/lgtm`, PR автоматически сливается. Утверждающий SIG Docs должен оставлять комментарий с `/lgtm` только для тех изменений, которые не нуждаются в дополнительном техническом обзоре. + +### Как стать утверждающим + +Если вы соответствуете [требованием](https://github.com/kubernetes/community/blob/master/community-membership.md#approver), вы можете стать утверждающим SIG Docs. Утверждающие в других SIG-группах должны подать новую заявку для получения статуса утверждающего в SIG Docs. + +Для отправки заявки откройте пулреквест с добавлением самого себя в секцию `approvers` [корневого файла OWNERS](https://github.com/kubernetes/website/blob/master/OWNERS) в репозитории `kubernetes/website`. Запросите проверку вашего пулреквеста одному или нескольким текущим утверждающим в группе SIG Docs. + +Если ваш пулреквест одобрен, вы становитесь утверждающим SIG Docs. Теперь бот [K8s-ci-robot](https://github.com/kubernetes/test-infra/tree/master/prow#bots-home) будет назначать и предлагать вас в качестве рецензента для проверки новых пулреквестов. + +После того, как ваша кандидатура будет одобрена, попросите текущего утверждающего SIG Docs добавить вас в GitHub-группу[@kubernetes/sig-docs-maintainers](https://github.com/orgs/kubernetes/teams/sig-docs-maintainers). Только члены GitHub-группы `kubernetes-website-admins` могут добавлять новых членов в какую-либо другую группу. + +### Обязанности утверждающего + +Утверждающие улучшают документацию, проверяя и сливая пулреквесты в репозитории сайта. Из-за того, эта роль предусматривает дополнительные привилегии, на утверждающих возлагаются дополнительные обязанности: + +- Утверждающие могут использовать команду `/approve`, которая сливает PR в репозиторий. + + Невнимательное слияние может нарушить работу сайта, поэтому имейте это в виду, когда объединяете какой-либо пулреквест. + +- Убедитесь, что предлагаемые изменения соответствуют [правилам по содержанию](/docs/contribute/style/content-guide/#contributing-content). + + Если вы сомневаетесь или вы не уверены в чем-либо, не стесняйтесь обращаться для дополнительной проверки. + +- Проверьте, что тесты на Netlify пройдены успешно, перед тем как написать комментарий с `/approve` в PR. + + Netlify tests must pass before approving + +- Перед одобрением пулреквеста перейдите на предварительный просмотр сайта на Netlify для сделанных изменений в PR, и убедитесь, что всё содержимое выглядит хорошо. + +- Участвуйте в [графике дежурства смотрителя PR](https://github.com/kubernetes/website/wiki/PR-Wranglers), чтобы вас назначили дежурным проверяющим на неделю. SIG Docs ожидает, что все утверждающие примут участие в этом графике. За подробностям обратитесь к странице [Be the PR Wrangler for a week](/docs/contribute/advanced#be-the-pr-wrangler-for-a-week). + +## Председатель SIG Docs + +Каждая SIG-группа, включая SIG Docs, выбирает одного или нескольких членов из своей SIG-группы в качестве председателей. Это координаторы между SIG Docs и другими подразделениями в организации Kubernetes. От таких людей требуются обширные знания о структуре проекта Kubernetes в целом и как функционирует группа SIG Docs внутри неё. Смотрите раздел [Руководство](https://github.com/kubernetes/community/tree/master/sig-docs#leadership), чтобы узнать текущий список председателей. + +## Команды SIG Docs и автоматизация + +Автоматизация в SIG Docs основывается на двух разных механизмах: +группы GitHub и файлы OWNERS. + +### GitHub-группы + +Группа SIG Docs представлена двумя командами на GitHub: + + - [@kubernetes/sig-docs-maintainers](https://github.com/orgs/kubernetes/teams/sig-docs-maintainers) + - [@kubernetes/sig-docs-pr-reviews](https://github.com/orgs/kubernetes/teams/sig-docs-pr-reviews) + +На каждую из них можно сослаться по имени (`@name`) в комментариях на GitHub, чтобы общаться со всеми участниками в этой группе. + +Эти команды пересекаются, но назначение у них разное. Для назначения людей на ишью, пулреквестов и поддержки одобрений в PR бот использует информацию из файлов OWNERS. + +### Файлы OWNERS и вступительная часть + +Проект Kubernetes использует инструмент автоматизации под названием prow, чтобы автоматизировать процесс, связанный с ишью и пулреквестами на GitHub. [Репозиторий сайта Kubernetes](https://github.com/kubernetes/website) использует два [плагина prow](https://github.com/kubernetes/test-infra/tree/master/prow/plugins): + +- blunderbuss +- approve + +Все эти плагины используют файлы [OWNERS](https://github.com/kubernetes/website/blob/master/OWNERS) и [OWNERS_ALIASES](https://github.com/kubernetes/website/blob/master/OWNERS_ALIASES) в корневой директории GitHub-репозитория `kubernetes/website`, чтобы контролировать работу prow по всему репозиторию. + +Файл OWNERS содержит список людей, которые являются рецензентами и утверждающими в SIG Docs. Файлы OWNERS также может быть в поддиректориях и могут переопределять тех, кто может выступать в качестве рецензента или утверждающего в изменениях файлов этой директории и её поддиректорий. Для получения дополнительной информации о файлах OWNERS в целом, перейдите в [OWNERS](https://github.com/kubernetes/community/blob/master/contributors/guide/owners.md). + +Кроме того, в каждом Markdown-файле могут быть указаны рецензенты и утверждающие в так называемой вступительной части (front-matter) в виде логинов участников или имён групп на GitHub. + +Таким образом файлы OWNERS и вступительная часть в Markdown-файлах определяет своего рода рекомендацию для бота, чтобы он знал, к кому обращаться за технической и редакционной проверкой каждого PR. + +## Как происходит слияние + +Когда пулреквест сливается в действующую ветку сайта (в данный момент это `master`), содержимое публикуется и становится общедоступным. Для обеспечения высокого качества публикуемого нами контента, мы доверяем слияние пулреквестов утверждающим SIG Docs. Ниже описан этот процесс. + +- Когда пулреквест имеет метки `lgtm` и `approve`, при этом у него нет метки `hold`, и то же время все тесты успешно проходят, то пулреквест автоматически сливается. +- Члены организации Kubernetes и утверждающие SIG Docs могут оставлять комментарии со специальными командами, которые блокирует автоматическое объединение пулреквеста (добавление комментарий с текстом `/hold` или удаление ранее установленной метки `/lgtm`). +- Любой участник Kubernetes может добавить метку `lgtm`, добавив комментарий, включающий в себя `/lgtm`. +- Только утверждающие SIG Docs могут слить пулреквест путём добавления комментария с `/approve`. Некоторые утверждающие также играют дополнительные роли, например, [смотрителя PR](#pr-wrangler) или [председателя SIG Docs](#председатель-sig-docs). + +{{% /capture %}} + +{{% capture whatsnext %}} + +Для получения дополнительной информации про участие в документации Kubernetes, посмотрите следующие страницы: + +- [Начало участия](/ru/docs/contribute/start/) +- [Правила оформления документации](/ru/docs/contribute/style/) + +{{% /capture %}} From 004bcd1ff8f6d14033651e58b3a98f587e4cf60c Mon Sep 17 00:00:00 2001 From: inductor Date: Tue, 18 Feb 2020 16:41:28 +0900 Subject: [PATCH 048/111] Second Japanese l10n work for release-1.16 (#19157) * update install kubeadm related doc (#18826) * modify terminology mechanism (#19148) --- .../concepts/architecture/cloud-controller.md | 4 +- .../api-extension/custom-resources.md | 2 +- .../extend-kubernetes/extend-cluster.md | 2 +- .../scheduling/scheduler-perf-tuning.md | 2 +- .../concepts/services-networking/service.md | 4 +- .../workloads/controllers/ttlafterfinished.md | 2 +- .../tools/kubeadm/control-plane-flags.md | 15 +- .../tools/kubeadm/create-cluster-kubeadm.md | 213 +++++++----------- .../tools/kubeadm/install-kubeadm.md | 7 +- 9 files changed, 110 insertions(+), 141 deletions(-) diff --git a/content/ja/docs/concepts/architecture/cloud-controller.md b/content/ja/docs/concepts/architecture/cloud-controller.md index 1e3e607d8b..9d76076fc7 100644 --- a/content/ja/docs/concepts/architecture/cloud-controller.md +++ b/content/ja/docs/concepts/architecture/cloud-controller.md @@ -8,7 +8,7 @@ weight: 30 クラウドコントローラマネージャー(CCM)のコンセプト(バイナリと混同しないでください)は、もともとクラウドベンダー固有のソースコードと、Kubernetesのコアソースコードを独立して進化させることが出来るように作られました。クラウドコントローラーマネージャーは、Kubernetesコントローラーマネージャー、APIサーバー、そしてスケジューラーのような他のマスターコンポーネントと並行して動きます。またKubernetesのアドオンとしても動かすことができ、その場合はKubernetes上で動きます。 -クラウドコントローラーマネージャーの設計は「プラグイン機構」をベースにしています。そうすることで、新しいクラウドプロバイダーがプラグインを使ってKubernetesと簡単に統合出来るようになります。新しいクラウドプロバイダーに向けてKubernetesのオンボーディングを行ったり、古いモデルを利用しているクラウドプロバイダーに、新しいCCMモデルに移行させるような計画があります。 +クラウドコントローラーマネージャーの設計は「プラグインメカニズム」をベースにしています。そうすることで、新しいクラウドプロバイダーがプラグインを使ってKubernetesと簡単に統合出来るようになります。新しいクラウドプロバイダーに向けてKubernetesのオンボーディングを行ったり、古いモデルを利用しているクラウドプロバイダーに、新しいCCMモデルに移行させるような計画があります。 このドキュメントでは、クラウドコントローラーマネージャーの背景にあるコンセプトと、それに関連する機能の詳細について話します。 @@ -91,7 +91,7 @@ CCMの大半の機能は、KCMから派生しています。前セクション この新しいモデルでは、kubeletはクラウド特有の情報無しでノードを初期化します。しかし、新しく作成されたノードにtaintを付けて、CCMがクラウド特有の情報でノードを初期化するまで、コンテナがスケジュールされないようにします。その後、taintを削除します。 -## プラグイン機構 +## プラグインメカニズム クラウドコントローラーマネージャーは、Goのインターフェースを利用してクラウドの実装をプラグイン化出来るようにしています。具体的には、[こちら](https://github.com/kubernetes/cloud-provider/blob/9b77dc1c384685cb732b3025ed5689dd597a5971/cloud.go#L42-L62)で定義されているクラウドプロバイダーインターフェースを利用しています。 diff --git a/content/ja/docs/concepts/extend-kubernetes/api-extension/custom-resources.md b/content/ja/docs/concepts/extend-kubernetes/api-extension/custom-resources.md index f83bc9ebc5..6d8fbc1e2e 100644 --- a/content/ja/docs/concepts/extend-kubernetes/api-extension/custom-resources.md +++ b/content/ja/docs/concepts/extend-kubernetes/api-extension/custom-resources.md @@ -170,7 +170,7 @@ CRD、またはアグリゲートAPI、どちらを使ってカスタムリソ | merge-patch | 新しいエンドポイントが`Content-Type: application/merge-patch+json`を用いたPATCHをサポート | | HTTPS | 新しいエンドポイントがHTTPSを利用 | | ビルトイン認証 | 拡張機能へのアクセスに認証のため、コアAPIサーバー(アグリゲーションレイヤー)を利用 | -| ビルトイン認可 | 拡張機能へのアクセスにコアAPIサーバーで使われている認可機構を再利用(例、RBAC) | +| ビルトイン認可 | 拡張機能へのアクセスにコアAPIサーバーで使われている認可メカニズムを再利用(例、RBAC) | | ファイナライザー | 外部リソースの削除が終わるまで、拡張リソースの削除をブロック | | Admission Webhooks | 拡張リソースの作成/更新/削除処理時に、デフォルト値の設定、バリデーションを実施 | | UI/CLI 表示 | kubectl、ダッシュボードで拡張リソースを表示 | diff --git a/content/ja/docs/concepts/extend-kubernetes/extend-cluster.md b/content/ja/docs/concepts/extend-kubernetes/extend-cluster.md index 6e6cacb3f3..b554f01819 100644 --- a/content/ja/docs/concepts/extend-kubernetes/extend-cluster.md +++ b/content/ja/docs/concepts/extend-kubernetes/extend-cluster.md @@ -121,7 +121,7 @@ Kubernetesはいくつかのビルトイン認証方式と、それらが要件 ### 認可 -[認可](/docs/reference/access-authn-authz/webhook/)は特定のユーザーがAPIリソースに対して、読み込み、書き込み、そしてその他の操作が可能かどうかを決定します。それはオブジェクト全体のレベルで機能し、任意のオブジェクトフィールドに基づいての区別は行いません。もしビルトインの認可機構が要件に合わない場合、[認可Webhook](/docs/reference/access-authn-authz/webhook/)が、ユーザー提供のコードを呼び出し認可の決定を行うことを可能にします。 +[認可](/docs/reference/access-authn-authz/webhook/)は特定のユーザーがAPIリソースに対して、読み込み、書き込み、そしてその他の操作が可能かどうかを決定します。それはオブジェクト全体のレベルで機能し、任意のオブジェクトフィールドに基づいての区別は行いません。もしビルトインの認可メカニズムが要件に合わない場合、[認可Webhook](/docs/reference/access-authn-authz/webhook/)が、ユーザー提供のコードを呼び出し認可の決定を行うことを可能にします。 ### 動的Admission Control diff --git a/content/ja/docs/concepts/scheduling/scheduler-perf-tuning.md b/content/ja/docs/concepts/scheduling/scheduler-perf-tuning.md index 8843138e73..ccc04a54f3 100644 --- a/content/ja/docs/concepts/scheduling/scheduler-perf-tuning.md +++ b/content/ja/docs/concepts/scheduling/scheduler-perf-tuning.md @@ -20,7 +20,7 @@ weight: 70 ## スコア付けするノードの割合 -Kubernetes 1.12以前では、Kube-schedulerがクラスター内の全てのノードに対して割り当て可能かをチェックし、実際に割り当て可能なノードのスコア付けをしていました。Kubernetes 1.12では新機能を追加し、ある数の割り当て可能なノードが見つかった時点で、割り当て可能なノードの探索を止めれるようになりました。これにより大規模なクラスターにおけるスケジューラーのパフォーマンスが向上しました。その数はクラスターのサイズの割合(%)として指定されます。この割合は`percentageOfNodesToScore`というオプションの設定項目によって指定可能です。この値の範囲は1から100までです。100より大きい値は100%として扱われます。0を指定したときは、この設定オプションを指定しないものとして扱われます。Kubernetes 1.14では、この値が指定されていないときは、スコア付けするノードの割合をクラスターのサイズに基づいて決定するための機構があります。この機構では100ノードのクラスターに対しては50%の割合とするような線形な式を使用します。5000ノードのクラスターに対しては10%となります。自動で算出される割合の最低値は5%となります。言い換えると、クラスターの規模がどれだけ大きくても、ユーザーがこの値を5未満に設定しない限りスケジューラーは少なくても5%のクラスター内のノードをスコア付けすることになります。 +Kubernetes 1.12以前では、Kube-schedulerがクラスター内の全てのノードに対して割り当て可能かをチェックし、実際に割り当て可能なノードのスコア付けをしていました。Kubernetes 1.12では新機能を追加し、ある数の割り当て可能なノードが見つかった時点で、割り当て可能なノードの探索を止めれるようになりました。これにより大規模なクラスターにおけるスケジューラーのパフォーマンスが向上しました。その数はクラスターのサイズの割合(%)として指定されます。この割合は`percentageOfNodesToScore`というオプションの設定項目によって指定可能です。この値の範囲は1から100までです。100より大きい値は100%として扱われます。0を指定したときは、この設定オプションを指定しないものとして扱われます。Kubernetes 1.14では、この値が指定されていないときは、スコア付けするノードの割合をクラスターのサイズに基づいて決定するためのメカニズムがあります。このメカニズムでは100ノードのクラスターに対しては50%の割合とするような線形な式を使用します。5000ノードのクラスターに対しては10%となります。自動で算出される割合の最低値は5%となります。言い換えると、クラスターの規模がどれだけ大きくても、ユーザーがこの値を5未満に設定しない限りスケジューラーは少なくても5%のクラスター内のノードをスコア付けすることになります。 `percentageOfNodesToScore`の値を50%に設定する例は下記のとおりです。 diff --git a/content/ja/docs/concepts/services-networking/service.md b/content/ja/docs/concepts/services-networking/service.md index 71c8795733..4c49ebd2a2 100644 --- a/content/ja/docs/concepts/services-networking/service.md +++ b/content/ja/docs/concepts/services-networking/service.md @@ -3,7 +3,7 @@ title: Service feature: title: サービスディスカバリーと負荷分散 description: > - Kubernetesでは、なじみのないサービスディスカバリーの機構を使用するためにユーザーがアプリケーションの修正をする必要はありません。KubernetesはPodにそれぞれのIPアドレス割り振りや、Podのセットに対する単一のDNS名を提供したり、それらのPodのセットに対する負荷分散が可能です。 + Kubernetesでは、なじみのないサービスディスカバリーのメカニズムを使用するためにユーザーがアプリケーションの修正をする必要はありません。KubernetesはPodにそれぞれのIPアドレス割り振りや、Podのセットに対する単一のDNS名を提供したり、それらのPodのセットに対する負荷分散が可能です。 content_template: templates/concept weight: 10 @@ -14,7 +14,7 @@ weight: 10 {{< glossary_definition term_id="service" length="short" >}} -Kubernetesでは、なじみのないサービスディスカバリーの機構を使用するためにユーザーがアプリケーションの修正をする必要はありません。 +Kubernetesでは、なじみのないサービスディスカバリーのメカニズムを使用するためにユーザーがアプリケーションの修正をする必要はありません。 KubernetesはPodにそれぞれのIPアドレス割り振りや、Podのセットに対する単一のDNS名を提供したり、それらのPodのセットに対する負荷分散が可能です。 {{% /capture %}} diff --git a/content/ja/docs/concepts/workloads/controllers/ttlafterfinished.md b/content/ja/docs/concepts/workloads/controllers/ttlafterfinished.md index aed6b33169..ee1dea77eb 100644 --- a/content/ja/docs/concepts/workloads/controllers/ttlafterfinished.md +++ b/content/ja/docs/concepts/workloads/controllers/ttlafterfinished.md @@ -9,7 +9,7 @@ weight: 65 {{< feature-state for_k8s_version="v1.12" state="alpha" >}} -TTLコントローラーは実行を終えたリソースオブジェクトのライフタイムを制御するためのTTL機構を提供します。 +TTLコントローラーは実行を終えたリソースオブジェクトのライフタイムを制御するためのTTLメカニズムを提供します。 TTLコントローラーは現在[Job](/docs/concepts/workloads/controllers/jobs-run-to-completion/)のみ扱っていて、将来的にPodやカスタムリソースなど、他のリソースの実行終了を扱えるように拡張される予定です。 α版の免責事項: この機能は現在α版の機能で、[Feature Gate](/docs/reference/command-line-tools-reference/feature-gates/)の`TTLAfterFinished`を有効にすることで使用可能です。 diff --git a/content/ja/docs/setup/production-environment/tools/kubeadm/control-plane-flags.md b/content/ja/docs/setup/production-environment/tools/kubeadm/control-plane-flags.md index 89ea61eb3e..5393e15b91 100644 --- a/content/ja/docs/setup/production-environment/tools/kubeadm/control-plane-flags.md +++ b/content/ja/docs/setup/production-environment/tools/kubeadm/control-plane-flags.md @@ -17,11 +17,16 @@ kubeadmの`ClusterConfiguration`オブジェクトはAPIServer、ControllerManag `extraArgs` の項目は `キー: 値` のペアです。コントロールプレーンの構成要素のフラグを上書きするには: -1. 設定内容に適切な項目を追加 -2. フラグを追加して項目を上書き +1. 設定内容に適切な項目を追加 +2. フラグを追加して項目を上書き +3. `--config <任意の設定YAMLファイル>`で`kubeadm init`を実行 各設定項目のより詳細な情報は[APIリファレンスのページ](https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm#ClusterConfiguration)を参照してください。 +{{< note >}} +`kubeadm config print init-defaults`を実行し、選択したファイルに出力を保存することで、デフォルト値で`ClusterConfiguration`オブジェクトを生成できます。 +{{< /note >}} + {{% /capture %}} {{% capture body %}} @@ -34,7 +39,7 @@ Example usage: ```yaml apiVersion: kubeadm.k8s.io/v1beta2 kind: ClusterConfiguration -kubernetesVersion: v1.13.0 +kubernetesVersion: v1.16.0 apiServer: extraArgs: advertise-address: 192.168.0.103 @@ -51,7 +56,7 @@ Example usage: ```yaml apiVersion: kubeadm.k8s.io/v1beta2 kind: ClusterConfiguration -kubernetesVersion: v1.13.0 +kubernetesVersion: v1.16.0 controllerManager: extraArgs: cluster-signing-key-file: /home/johndoe/keys/ca.key @@ -67,7 +72,7 @@ Example usage: ```yaml apiVersion: kubeadm.k8s.io/v1beta2 kind: ClusterConfiguration -kubernetesVersion: v1.13.0 +kubernetesVersion: v1.16.0 scheduler: extraArgs: address: 0.0.0.0 diff --git a/content/ja/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm.md b/content/ja/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm.md index 3d8f65775b..a79e3367d1 100644 --- a/content/ja/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm.md +++ b/content/ja/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm.md @@ -1,5 +1,5 @@ --- -title: kubeadmを使用したシングルマスタークラスターの作成 +title: kubeadmを使用したシングルコントロールプレーンクラスターの作成 content_template: templates/task weight: 30 --- @@ -33,17 +33,6 @@ but you may also build them from source for other OSes. ### kubeadmの成熟度 -| Area | Maturity Level | -|---------------------------|--------------- | -| Command line UX | GA | -| Implementation | GA | -| Config file API | Beta | -| CoreDNS | GA | -| kubeadm alpha subcommands | Alpha | -| High availability | Beta | -| DynamicKubeletConfig | Alpha | - - kubeadm's overall feature state is **GA**. Some sub-features, like the configuration file API are still under active development. The implementation of creating the cluster may change slightly as the tool evolves, but the overall implementation should be pretty stable. @@ -59,16 +48,10 @@ timeframe; which also applies to `kubeadm`. | Kubernetes version | Release month | End-of-life-month | |--------------------|----------------|-------------------| -| v1.6.x | March 2017 | December 2017 | -| v1.7.x | June 2017 | March 2018 | -| v1.8.x | September 2017 | June 2018 | -| v1.9.x | December 2017 | September 2018   | -| v1.10.x | March 2018 | December 2018   | -| v1.11.x | June 2018 | March 2019   | -| v1.12.x | September 2018 | June 2019   | -| v1.13.x | December 2018 | September 2019   | -| v1.14.x | March 2019 | December 2019   | -| v1.15.x | June 2019 | March 2020   | +| v1.13.x | December 2018 | September 2019 | +| v1.14.x | March 2019 | December 2019 | +| v1.15.x | June 2019 | March 2020 | +| v1.16.x | September 2019 | June 2020 | {{% /capture %}} @@ -87,7 +70,7 @@ timeframe; which also applies to `kubeadm`. ## 目的 -* Install a single master Kubernetes cluster or [high availability cluster](/ja/docs/setup/production-environment/tools/kubeadm/high-availability/) +* Install a single control-plane Kubernetes cluster or [high availability cluster](/ja/docs/setup/production-environment/tools/kubeadm/high-availability/) * Install a Pod network on the cluster so that your Pods can talk to each other @@ -103,50 +86,75 @@ apt-get upgrade` or `yum update` to get the latest version of kubeadm. When you upgrade, the kubelet restarts every few seconds as it waits in a crashloop for kubeadm to tell it what to do. This crashloop is expected and normal. -After you initialize your master, the kubelet runs normally. +After you initialize your control-plane, the kubelet runs normally. {{< /note >}} -### マスターの初期化 +### コントロールプレーンノードの初期化 The control-plane node is the machine where the control plane components run, including etcd (the cluster database) and the API server (which the kubectl CLI communicates with). -1. Choose a pod network add-on, and verify whether it requires any arguments to +1. (Recommended) If you have plans to upgrade this single control-plane kubeadm cluster +to high availability you should specify the `--control-plane-endpoint` to set the shared endpoint +for all control-plane nodes. Such an endpoint can be either a DNS name or an IP address of a load-balancer. +1. Choose a Pod network add-on, and verify whether it requires any arguments to be passed to kubeadm initialization. Depending on which third-party provider you choose, you might need to set the `--pod-network-cidr` to -a provider-specific value. See [Installing a pod network add-on](#pod-network). +a provider-specific value. See [Installing a Pod network add-on](#pod-network). 1. (Optional) Since version 1.14, kubeadm will try to detect the container runtime on Linux by using a list of well known domain socket paths. To use different container runtime or if there are more than one installed on the provisioned node, specify the `--cri-socket` argument to `kubeadm init`. See [Installing runtime](/ja/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#installing-runtime). 1. (Optional) Unless otherwise specified, kubeadm uses the network interface associated -with the default gateway to advertise the master's IP. To use a different -network interface, specify the `--apiserver-advertise-address=` argument +with the default gateway to set the advertise address for this particular control-plane node's API server. +To use a different network interface, specify the `--apiserver-advertise-address=` argument to `kubeadm init`. To deploy an IPv6 Kubernetes cluster using IPv6 addressing, you must specify an IPv6 address, for example `--apiserver-advertise-address=fd00::101` 1. (Optional) Run `kubeadm config images pull` prior to `kubeadm init` to verify connectivity to gcr.io registries. -Now run: +To initialize the control-plane node run: ```bash kubeadm init ``` +### Considerations about apiserver-advertise-address and ControlPlaneEndpoint + +While `--apiserver-advertise-address` can be used to set the advertise address for this particular +control-plane node's API server, `--control-plane-endpoint` can be used to set the shared endpoint +for all control-plane nodes. + +`--control-plane-endpoint` allows IP addresses but also DNS names that can map to IP addresses. +Please contact your network administrator to evaluate possible solutions with respect to such mapping. + +Here is an example mapping: + +``` +192.168.0.102 cluster-endpoint +``` + +Where `192.168.0.102` is the IP address of this node and `cluster-endpoint` is a custom DNS name that maps to this IP. +This will allow you to pass `--control-plane-endpoint=cluster-endpoint` to `kubeadm init` and pass the same DNS name to +`kubeadm join`. Later you can modify `cluster-endpoint` to point to the address of your load-balancer in an +high availability scenario. + +Turning a single control plane cluster created without `--control-plane-endpoint` into a highly available cluster +is not supported by kubeadm. + ### 詳細 For more information about `kubeadm init` arguments, see the [kubeadm reference guide](/ja/docs/reference/setup-tools/kubeadm/kubeadm/). For a complete list of configuration options, see the [configuration file documentation](/ja/docs/reference/setup-tools/kubeadm/kubeadm-init/#config-file). -To customize control plane components, including optional IPv6 assignment to liveness probe for control plane components and etcd server, provide extra arguments to each component as documented in [custom arguments](/ja/docs/admin/kubeadm#custom-args). +To customize control plane components, including optional IPv6 assignment to liveness probe for control plane components and etcd server, provide extra arguments to each component as documented in [custom arguments](/ja/docs/setup/production-environment/tools/kubeadm/control-plane-flags/). To run `kubeadm init` again, you must first [tear down the cluster](#tear-down). -If you join a node with a different architecture to your cluster, create a separate -Deployment or DaemonSet for `kube-proxy` and `kube-dns` on the node. This is because the Docker images for these -components do not currently support multi-architecture. +If you join a node with a different architecture to your cluster, make sure that your deployed DaemonSets +have container image support for this architecture. `kubeadm init` first runs a series of prechecks to ensure that the machine is ready to run Kubernetes. These prechecks expose warnings and exit on errors. `kubeadm init` @@ -165,14 +173,14 @@ The output should look like: [certs] Using certificateDir folder "/etc/kubernetes/pki" [certs] Generating "etcd/ca" certificate and key [certs] Generating "etcd/server" certificate and key -[certs] etcd/server serving cert is signed for DNS names [kubeadm-master localhost] and IPs [10.138.0.4 127.0.0.1 ::1] +[certs] etcd/server serving cert is signed for DNS names [kubeadm-cp localhost] and IPs [10.138.0.4 127.0.0.1 ::1] [certs] Generating "etcd/healthcheck-client" certificate and key [certs] Generating "etcd/peer" certificate and key -[certs] etcd/peer serving cert is signed for DNS names [kubeadm-master localhost] and IPs [10.138.0.4 127.0.0.1 ::1] +[certs] etcd/peer serving cert is signed for DNS names [kubeadm-cp localhost] and IPs [10.138.0.4 127.0.0.1 ::1] [certs] Generating "apiserver-etcd-client" certificate and key [certs] Generating "ca" certificate and key [certs] Generating "apiserver" certificate and key -[certs] apiserver serving cert is signed for DNS names [kubeadm-master kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 10.138.0.4] +[certs] apiserver serving cert is signed for DNS names [kubeadm-cp kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 10.138.0.4] [certs] Generating "apiserver-kubelet-client" certificate and key [certs] Generating "front-proxy-ca" certificate and key [certs] Generating "front-proxy-client" certificate and key @@ -191,9 +199,9 @@ The output should look like: [apiclient] All control plane components are healthy after 31.501735 seconds [uploadconfig] storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace [kubelet] Creating a ConfigMap "kubelet-config-X.Y" in namespace kube-system with the configuration for the kubelets in the cluster -[patchnode] Uploading the CRI Socket information "/var/run/dockershim.sock" to the Node API object "kubeadm-master" as an annotation -[mark-control-plane] Marking the node kubeadm-master as control-plane by adding the label "node-role.kubernetes.io/master=''" -[mark-control-plane] Marking the node kubeadm-master as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule] +[patchnode] Uploading the CRI Socket information "/var/run/dockershim.sock" to the Node API object "kubeadm-cp" as an annotation +[mark-control-plane] Marking the node kubeadm-cp as control-plane by adding the label "node-role.kubernetes.io/master=''" +[mark-control-plane] Marking the node kubeadm-cp as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule] [bootstrap-token] Using token: [bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles [bootstraptoken] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials @@ -203,7 +211,7 @@ The output should look like: [addons] Applied essential addon: CoreDNS [addons] Applied essential addon: kube-proxy -Your Kubernetes master has initialized successfully! +Your Kubernetes control-plane has initialized successfully! To start using your cluster, you need to run the following as a regular user: @@ -211,14 +219,14 @@ To start using your cluster, you need to run the following as a regular user: sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config -You should now deploy a pod network to the cluster. +You should now deploy a Pod network to the cluster. Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: /docs/concepts/cluster-administration/addons/ You can now join any number of machines by running the following on each node as root: - kubeadm join : --token --discovery-token-ca-cert-hash sha256: + kubeadm join : --token --discovery-token-ca-cert-hash sha256: ``` To make kubectl work for your non-root user, run these commands, which are @@ -251,13 +259,13 @@ created, and deleted with the `kubeadm token` command. See the This section contains important information about installation and deployment order. Read it carefully before proceeding. {{< /caution >}} -You must install a pod network add-on so that your pods can communicate with +You must install a Pod network add-on so that your Pods can communicate with each other. **The network must be deployed before any applications. Also, CoreDNS will not start up before a network is installed. kubeadm only supports Container Network Interface (CNI) based networks (and does not support kubenet).** -Several projects provide Kubernetes pod networks using CNI, some of which also +Several projects provide Kubernetes Pod networks using CNI, some of which also support [Network Policy](/ja/docs/concepts/services-networking/networkpolicies/). See the [add-ons page](/ja/docs/concepts/cluster-administration/addons/) for a complete list of available network add-ons. - IPv6 support was added in [CNI v0.6.0](https://github.com/containernetworking/cni/releases/tag/v0.6.0). - [CNI bridge](https://github.com/containernetworking/plugins/blob/master/plugins/main/bridge/README.md) and [local-ipam](https://github.com/containernetworking/plugins/blob/master/plugins/ipam/host-local/README.md) are the only supported IPv6 network plugins in Kubernetes version 1.9. @@ -268,24 +276,16 @@ Make sure that your network manifest supports RBAC. Also, beware, that your Pod network must not overlap with any of the host networks as this can cause issues. If you find a collision between your network plugin’s preferred Pod network and some of your host networks, you should think of a suitable CIDR replacement and use that during `kubeadm init` with `--pod-network-cidr` and as a replacement in your network plugin’s YAML. -You can install a pod network add-on with the following command: +You can install a Pod network add-on with the following command on the control-plane node or a node that has the kubeconfig credentials: ```bash kubectl apply -f ``` -You can install only one pod network per cluster. +You can install only one Pod network per cluster. +Below you can find installation instructions for some popular Pod network plugins: {{< tabs name="tabs-pod-install" >}} -{{% tab name="Choose one..." %}} -Please select one of the tabs to see installation instructions for the respective third-party Pod Network Provider. -{{% /tab %}} - -{{% tab name="AWS VPC" %}} -AWS VPC CNI provides native AWS VPC networking to Kubernetes clusters. - -For installation, please refer to the [AWS VPC CNI setup guide](https://github.com/aws/amazon-vpc-cni-k8s#setup). -{{% /tab %}} {{% tab name="Calico" %}} For more information about using Calico, see [Quickstart for Calico on Kubernetes](https://docs.projectcalico.org/latest/getting-started/kubernetes/), [Installing Calico for policy and networking](https://docs.projectcalico.org/latest/getting-started/kubernetes/installation/calico), and other related resources. @@ -296,39 +296,18 @@ For Calico to work correctly, you need to pass `--pod-network-cidr=192.168.0.0/1 kubectl apply -f https://docs.projectcalico.org/v3.8/manifests/calico.yaml ``` -{{% /tab %}} -{{% tab name="Canal" %}} -Canal uses Calico for policy and Flannel for networking. Refer to the Calico documentation for the [official getting started guide](https://docs.projectcalico.org/latest/getting-started/kubernetes/installation/flannel). - -For Canal to work correctly, `--pod-network-cidr=10.244.0.0/16` has to be passed to `kubeadm init`. Note that Canal works on `amd64` only. - -```shell -kubectl apply -f https://docs.projectcalico.org/v3.8/manifests/canal.yaml -``` - {{% /tab %}} {{% tab name="Cilium" %}} -For more information about using Cilium with Kubernetes, see [Kubernetes Install guide for Cilium](https://docs.cilium.io/en/stable/kubernetes/). - For Cilium to work correctly, you must pass `--pod-network-cidr=10.217.0.0/16` to `kubeadm init`. -These commands will deploy Cilium with its own etcd managed by etcd operator. - -_Note_: If you are running kubeadm in a single node please untaint it so that -etcd-operator pods can be scheduled in the control-plane node. - -```shell -kubectl taint nodes node-role.kubernetes.io/master:NoSchedule- -``` - To deploy Cilium you just need to run: ```shell -kubectl create -f https://raw.githubusercontent.com/cilium/cilium/v1.5/examples/kubernetes/1.14/cilium.yaml +kubectl create -f https://raw.githubusercontent.com/cilium/cilium/v1.6/install/kubernetes/quick-install.yaml ``` -Once all Cilium pods are marked as `READY`, you start using your cluster. +Once all Cilium Pods are marked as `READY`, you start using your cluster. ```shell kubectl get pods -n kube-system --selector=k8s-app=cilium @@ -339,6 +318,10 @@ NAME READY STATUS RESTARTS AGE cilium-drxkl 1/1 Running 0 18m ``` +Cilium can be used as a replacement for kube-proxy, see [Kubernetes without kube-proxy](https://docs.cilium.io/en/stable/gettingstarted/kubeproxy-free). + +For more information about using Cilium with Kubernetes, see [Kubernetes Install guide for Cilium](https://docs.cilium.io/en/stable/kubernetes/). + {{% /tab %}} {{% tab name="Contiv-VPP" %}} @@ -366,49 +349,25 @@ Note that `flannel` works on `amd64`, `arm`, `arm64`, `ppc64le` and `s390x` unde Windows (`amd64`) is claimed as supported in v0.11.0 but the usage is undocumented. ```shell -kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/62e44c867a2846fefb68bd5f178daf4da3095ccb/Documentation/kube-flannel.yml +kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/2140ac876ef134e0ed5af15c65e414cf26827915/Documentation/kube-flannel.yml ``` For more information about `flannel`, see [the CoreOS flannel repository on GitHub ](https://github.com/coreos/flannel). {{% /tab %}} -{{% tab name="JuniperContrail/TungstenFabric" %}} -Provides overlay SDN solution, delivering multicloud networking, hybrid cloud networking, -simultaneous overlay-underlay support, network policy enforcement, network isolation, -service chaining and flexible load balancing. - -There are multiple, flexible ways to install JuniperContrail/TungstenFabric CNI. - -Kindly refer to this quickstart: [TungstenFabric](https://tungstenfabric.github.io/website/) -{{% /tab %}} - {{% tab name="Kube-router" %}} Set `/proc/sys/net/bridge/bridge-nf-call-iptables` to `1` by running `sysctl net.bridge.bridge-nf-call-iptables=1` to pass bridged IPv4 traffic to iptables' chains. This is a requirement for some CNI plugins to work, for more information please see [here](/ja/docs/concepts/cluster-administration/network-plugins/#network-plugin-requirements). -Kube-router relies on kube-controller-manager to allocate pod CIDR for the nodes. Therefore, use `kubeadm init` with the `--pod-network-cidr` flag. +Kube-router relies on kube-controller-manager to allocate Pod CIDR for the nodes. Therefore, use `kubeadm init` with the `--pod-network-cidr` flag. -Kube-router provides pod networking, network policy, and high-performing IP Virtual Server(IPVS)/Linux Virtual Server(LVS) based service proxy. +Kube-router provides Pod networking, network policy, and high-performing IP Virtual Server(IPVS)/Linux Virtual Server(LVS) based service proxy. For information on setting up Kubernetes cluster with Kube-router using kubeadm, please see official [setup guide](https://github.com/cloudnativelabs/kube-router/blob/master/docs/kubeadm.md). {{% /tab %}} -{{% tab name="Romana" %}} -Set `/proc/sys/net/bridge/bridge-nf-call-iptables` to `1` by running `sysctl net.bridge.bridge-nf-call-iptables=1` -to pass bridged IPv4 traffic to iptables' chains. This is a requirement for some CNI plugins to work, for more information -please see [here](/ja/docs/concepts/cluster-administration/network-plugins/#network-plugin-requirements). - -The official Romana set-up guide is [here](https://github.com/romana/romana/tree/master/containerize#using-kubeadm). - -Romana works on `amd64` only. - -```shell -kubectl apply -f https://raw.githubusercontent.com/romana/romana/master/containerize/specs/romana-kubeadm.yml -``` -{{% /tab %}} - {{% tab name="Weave Net" %}} Set `/proc/sys/net/bridge/bridge-nf-call-iptables` to `1` by running `sysctl net.bridge.bridge-nf-call-iptables=1` to pass bridged IPv4 traffic to iptables' chains. This is a requirement for some CNI plugins to work, for more information @@ -428,16 +387,16 @@ kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl versio {{< /tabs >}} -Once a pod network has been installed, you can confirm that it is working by -checking that the CoreDNS pod is Running in the output of `kubectl get pods --all-namespaces`. -And once the CoreDNS pod is up and running, you can continue by joining your nodes. +Once a Pod network has been installed, you can confirm that it is working by +checking that the CoreDNS Pod is Running in the output of `kubectl get pods --all-namespaces`. +And once the CoreDNS Pod is up and running, you can continue by joining your nodes. If your network is not working or CoreDNS is not in the Running state, checkout our [troubleshooting docs](/ja/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm/). ### コントロールプレーンノードの隔離 -By default, your cluster will not schedule pods on the control-plane node for security -reasons. If you want to be able to schedule pods on the control-plane node, e.g. for a +By default, your cluster will not schedule Pods on the control-plane node for security +reasons. If you want to be able to schedule Pods on the control-plane node, e.g. for a single-machine Kubernetes cluster for development, run: ```bash @@ -454,21 +413,21 @@ taint "node-role.kubernetes.io/master:" not found This will remove the `node-role.kubernetes.io/master` taint from any nodes that have it, including the control-plane node, meaning that the scheduler will then be able -to schedule pods everywhere. +to schedule Pods everywhere. ### ノードの追加 {#join-nodes} -The nodes are where your workloads (containers and pods, etc) run. To add new nodes to your cluster do the following for each machine: +The nodes are where your workloads (containers and Pods, etc) run. To add new nodes to your cluster do the following for each machine: * SSH to the machine * Become root (e.g. `sudo su -`) * Run the command that was output by `kubeadm init`. For example: ``` bash -kubeadm join --token : --discovery-token-ca-cert-hash sha256: +kubeadm join --token : --discovery-token-ca-cert-hash sha256: ``` -If you do not have the token, you can get it by running the following command on the master node: +If you do not have the token, you can get it by running the following command on the control-plane node: ``` bash kubeadm token list @@ -485,7 +444,7 @@ TOKEN TTL EXPIRES USAGES DESCRIPTION ``` By default, tokens expire after 24 hours. If you are joining a node to the cluster after the current token has expired, -you can create a new token by running the following command on the master node: +you can create a new token by running the following command on the control-plane node: ``` bash kubeadm token create @@ -497,7 +456,7 @@ The output is similar to this: 5didvk.d09sbcov8ph2amjw ``` -If you don't have the value of `--discovery-token-ca-cert-hash`, you can get it by running the following command chain on the master node: +If you don't have the value of `--discovery-token-ca-cert-hash`, you can get it by running the following command chain on the control-plane node: ``` bash openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | \ @@ -511,7 +470,7 @@ The output is similar to this: ``` {{< note >}} -To specify an IPv6 tuple for `:`, IPv6 address must be enclosed in square brackets, for example: `[fd00::101]:2073`. +To specify an IPv6 tuple for `:`, IPv6 address must be enclosed in square brackets, for example: `[fd00::101]:2073`. {{< /note >}} The output should look something like: @@ -522,24 +481,24 @@ The output should look something like: ... (log output of join workflow) ... Node join complete: -* Certificate signing request sent to master and response +* Certificate signing request sent to control-plane and response received. * Kubelet informed of new secure connection details. -Run 'kubectl get nodes' on the master to see this machine join. +Run 'kubectl get nodes' on control-plane to see this machine join. ``` A few seconds later, you should notice this node in the output from `kubectl get -nodes` when run on the master. +nodes` when run on the control-plane node. -### (任意) マスター以外のマシンからのクラスター操作 +### (任意)コントロールプレーンノード以外のマシンからのクラスター操作 In order to get a kubectl on some other computer (e.g. laptop) to talk to your -cluster, you need to copy the administrator kubeconfig file from your master +cluster, you need to copy the administrator kubeconfig file from your control-plane node to your workstation like this: ``` bash -scp root@:/etc/kubernetes/admin.conf . +scp root@:/etc/kubernetes/admin.conf . kubectl --kubeconfig ./admin.conf get nodes ``` @@ -563,7 +522,7 @@ If you want to connect to the API Server from outside the cluster you can use `kubectl proxy`: ```bash -scp root@:/etc/kubernetes/admin.conf . +scp root@:/etc/kubernetes/admin.conf . kubectl --kubeconfig ./admin.conf proxy ``` @@ -575,7 +534,7 @@ To undo what kubeadm did, you should first [drain the node](/ja/docs/reference/generated/kubectl/kubectl-commands#drain) and make sure that the node is empty before shutting it down. -Talking to the master with the appropriate credentials, run: +Talking to the control-plane node with the appropriate credentials, run: ```bash kubectl drain --delete-local-data --force --ignore-daemonsets @@ -622,6 +581,8 @@ control of your Kubernetes cluster. * Learn about kubeadm's advanced usage in the [kubeadm reference documentation](/ja/docs/reference/setup-tools/kubeadm/kubeadm) * Learn more about Kubernetes [concepts](/ja/docs/concepts/) and [`kubectl`](/ja/docs/user-guide/kubectl-overview/). * Configure log rotation. You can use **logrotate** for that. When using Docker, you can specify log rotation options for Docker daemon, for example `--log-driver=json-file --log-opt=max-size=10m --log-opt=max-file=5`. See [Configure and troubleshoot the Docker daemon](https://docs.docker.com/engine/admin/) for more details. +* See the [Cluster Networking](/docs/concepts/cluster-administration/networking/) page for a bigger list +of Pod network add-ons. ## フィードバック {#feedback} diff --git a/content/ja/docs/setup/production-environment/tools/kubeadm/install-kubeadm.md b/content/ja/docs/setup/production-environment/tools/kubeadm/install-kubeadm.md index 40d46f1912..9a7973469f 100644 --- a/content/ja/docs/setup/production-environment/tools/kubeadm/install-kubeadm.md +++ b/content/ja/docs/setup/production-environment/tools/kubeadm/install-kubeadm.md @@ -56,6 +56,9 @@ Linuxでは、カーネルのiptablesサブシステムの最新の代替品と {{< tabs name="iptables_legacy" >}} {{% tab name="Debian or Ubuntu" %}} ```bash +# レガシーバイナリがインストールされていることを確認してください +sudo apt-get install -y iptables arptables ebtables + sudo update-alternatives --set iptables /usr/sbin/iptables-legacy sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy sudo update-alternatives --set arptables /usr/sbin/arptables-legacy @@ -189,7 +192,7 @@ systemctl enable --now kubelet `net.bridge.bridge-nf-call-iptables` is set to 1 in your `sysctl` config, e.g. ```bash - cat < /etc/sysctl.d/k8s.conf + cat < /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF @@ -268,6 +271,6 @@ kubeadmで問題が発生した場合は、[トラブルシューティング](/ {{% capture whatsnext %}} -* [kubeadmを使用したシングルマスタークラスターの作成](/ja/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/) +* [kubeadmを使用したシングルコントロールプレーンクラスターの作成](/ja/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/) {{% /capture %}} From 1513a7b29a0dc3fdb7b963cfa93caf50a1f38075 Mon Sep 17 00:00:00 2001 From: Andrew Allbright Date: Tue, 18 Feb 2020 19:42:25 -0500 Subject: [PATCH 049/111] latin phrase removed (#19180) --- .../docs/reference/access-authn-authz/service-accounts-admin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/reference/access-authn-authz/service-accounts-admin.md b/content/en/docs/reference/access-authn-authz/service-accounts-admin.md index 329b8a1b4a..5c2dd3ddc5 100644 --- a/content/en/docs/reference/access-authn-authz/service-accounts-admin.md +++ b/content/en/docs/reference/access-authn-authz/service-accounts-admin.md @@ -18,7 +18,7 @@ incomplete features are referred to in order to better describe service accounts {{% /capture %}} {{% capture body %}} -## User accounts vs service accounts +## User accounts versus service accounts Kubernetes distinguishes between the concept of a user account and a service account for a number of reasons: From 2d0bde0458d505bc6c2771544c5a5eea27dbf1c9 Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Wed, 19 Feb 2020 02:54:24 +0200 Subject: [PATCH 050/111] kubeadm: add TS guide note about CoreOS read-only /usr (#19166) * kubeadm: add TS guide note about CoreOS read-only /usr * Update content/en/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm.md Co-Authored-By: Tim Bannister Co-authored-by: Tim Bannister --- .../tools/kubeadm/troubleshooting-kubeadm.md | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/content/en/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm.md b/content/en/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm.md index 2f51d5efd7..31f94ef137 100644 --- a/content/en/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm.md +++ b/content/en/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm.md @@ -319,4 +319,46 @@ There are at least two workarounds: ```bash kubectl taint nodes NODE_NAME role.kubernetes.io/master:NoSchedule- ``` + +## `/usr` is mounted read-only on nodes {#usr-mounted-read-only} + +On Linux distributions such as Fedora CoreOS, the directory `/usr` is mounted as a read-only filesystem. +For [flex-volume support](https://github.com/kubernetes/community/blob/ab55d85/contributors/devel/sig-storage/flexvolume.md), +Kubernetes components like the kubelet and kube-controller-manager use the default path of +`/usr/libexec/kubernetes/kubelet-plugins/volume/exec/`, yet the flex-volume directory _must be writeable_ +for the feature to work. + +To workaround this issue you can configure the flex-volume directory using the kubeadm +[configuration file](https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2). + +On the primary control-plane Node (created using `kubeadm init`) pass the following +file using `--config`: + +```yaml +apiVersion: kubeadm.k8s.io/v1beta2 +kind: InitConfiguration +nodeRegistration: + kubeletExtraArgs: + volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/" +--- +apiVersion: kubeadm.k8s.io/v1beta2 +kind: ClusterConfiguration +controllerManager: + extraArgs: + flex-volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/" +``` + +On joining Nodes: + +```yaml +apiVersion: kubeadm.k8s.io/v1beta2 +kind: JoinConfiguration +nodeRegistration: + kubeletExtraArgs: + volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/" +``` + +Alternatively, you can modify `/etc/fstab` to make the `/usr` mount writeable, but please +be advised that this is modifying a design principle of the Linux distribution. + {{% /capture %}} From 470f932dd8649592152b0388c653d114e81ee74d Mon Sep 17 00:00:00 2001 From: Andrew Allbright Date: Wed, 19 Feb 2020 03:14:25 -0500 Subject: [PATCH 051/111] Latin Abbreviations "vs" Updated to "versus" (#19181) * grep -lR ' vs ' ./content/en/docs | xargs sed -i '' -e 's/ vs / versus /g' * Update content/en/docs/concepts/configuration/overview.md Co-Authored-By: Tim Bannister * Update content/en/docs/concepts/policy/resource-quotas.md Co-Authored-By: Tim Bannister Co-authored-by: Tim Bannister --- content/en/docs/concepts/configuration/overview.md | 3 +-- .../extend-kubernetes/api-extension/custom-resources.md | 2 +- content/en/docs/concepts/policy/resource-quotas.md | 2 +- .../docs/reference/access-authn-authz/admission-controllers.md | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/content/en/docs/concepts/configuration/overview.md b/content/en/docs/concepts/configuration/overview.md index 1f67727322..ca56089b01 100644 --- a/content/en/docs/concepts/configuration/overview.md +++ b/content/en/docs/concepts/configuration/overview.md @@ -30,7 +30,7 @@ This is a living document. If you think of something that is not on this list bu - Put object descriptions in annotations, to allow better introspection. -## "Naked" Pods vs ReplicaSets, Deployments, and Jobs +## "Naked" Pods versus ReplicaSets, Deployments, and Jobs {#naked-pods-vs-replicasets-deployments-and-jobs} - Don't use naked Pods (that is, Pods not bound to a [ReplicaSet](/docs/concepts/workloads/controllers/replicaset/) or [Deployment](/docs/concepts/workloads/controllers/deployment/)) if you can avoid it. Naked Pods will not be rescheduled in the event of a node failure. @@ -108,4 +108,3 @@ The caching semantics of the underlying image provider make even `imagePullPolic {{% /capture %}} - diff --git a/content/en/docs/concepts/extend-kubernetes/api-extension/custom-resources.md b/content/en/docs/concepts/extend-kubernetes/api-extension/custom-resources.md index 660d589169..c96ae1f5c7 100644 --- a/content/en/docs/concepts/extend-kubernetes/api-extension/custom-resources.md +++ b/content/en/docs/concepts/extend-kubernetes/api-extension/custom-resources.md @@ -202,7 +202,7 @@ When you create a custom resource, either via a CRDs or an AA, you get many feat | Finalizers | Block deletion of extension resources until external cleanup happens. | | Admission Webhooks | Set default values and validate extension resources during any create/update/delete operation. | | UI/CLI Display | Kubectl, dashboard can display extension resources. | -| Unset vs Empty | Clients can distinguish unset fields from zero-valued fields. | +| Unset versus Empty | Clients can distinguish unset fields from zero-valued fields. | | Client Libraries Generation | Kubernetes provides generic client libraries, as well as tools to generate type-specific client libraries. | | Labels and annotations | Common metadata across objects that tools know how to edit for core and custom resources. | diff --git a/content/en/docs/concepts/policy/resource-quotas.md b/content/en/docs/concepts/policy/resource-quotas.md index 14fde56066..92f43fe3a3 100644 --- a/content/en/docs/concepts/policy/resource-quotas.md +++ b/content/en/docs/concepts/policy/resource-quotas.md @@ -376,7 +376,7 @@ pods 0 10 * `Exist` * `DoesNotExist` -## Requests vs Limits +## Requests compared to Limits {#requests-vs-limits} When allocating compute resources, each container may specify a request and a limit value for either CPU or memory. The quota can be configured to quota either value. diff --git a/content/en/docs/reference/access-authn-authz/admission-controllers.md b/content/en/docs/reference/access-authn-authz/admission-controllers.md index 2e741afd76..2ab54051a4 100644 --- a/content/en/docs/reference/access-authn-authz/admission-controllers.md +++ b/content/en/docs/reference/access-authn-authz/admission-controllers.md @@ -737,7 +737,7 @@ phase, and therefore is the last admission controller to run. `MutatingAdmissionWebhook` appears before it in this list, because it runs in the mutating phase. - For earlier versions, there was no concept of validating vs mutating and the + For earlier versions, there was no concept of validating versus mutating and the admission controllers ran in the exact order specified. {{% /capture %}} From 601f33f4fda784d277e74f350bb8d96a16a14c57 Mon Sep 17 00:00:00 2001 From: "Jorge O. Castro" Date: Wed, 19 Feb 2020 11:24:26 -0500 Subject: [PATCH 052/111] Announce the contributor summit schedule (#19174) * Announce the contributor summit schedule Signed-off-by: Jorge O. Castro * Fix minor nits found during review Signed-off-by: Jorge O. Castro * Update content/en/blog/_posts/2020-02-18-Contributor-Summit-Amsterdam-Schedule-Announced.md Make the map URL easier to read. Co-Authored-By: Tim Bannister * Add contributor summit image Signed-off-by: Jorge O. Castro Co-authored-by: Tim Bannister --- ...tor-Summit-Amsterdam-Schedule-Announced.md | 45 ++++++++++++++++++ .../contribsummit.jpg | Bin 0 -> 246927 bytes 2 files changed, 45 insertions(+) create mode 100644 content/en/blog/_posts/2020-02-18-Contributor-Summit-Amsterdam-Schedule-Announced.md create mode 100644 static/images/blog/2020-02-18-Contributor-Summit-Amsterdam-Schedule-Announced/contribsummit.jpg diff --git a/content/en/blog/_posts/2020-02-18-Contributor-Summit-Amsterdam-Schedule-Announced.md b/content/en/blog/_posts/2020-02-18-Contributor-Summit-Amsterdam-Schedule-Announced.md new file mode 100644 index 0000000000..ae05bd8b9c --- /dev/null +++ b/content/en/blog/_posts/2020-02-18-Contributor-Summit-Amsterdam-Schedule-Announced.md @@ -0,0 +1,45 @@ +--- +layout: blog +title: "Contributor Summit Amsterdam Schedule Announced" +date: 2020-02-18 +slug: Contributor-Summit-Amsterdam-Schedule-Announced +--- + +**Authors:** Jeffrey Sica (Red Hat), Amanda Katona (VMware) + +tl;dr [Registration is open](https://events.linuxfoundation.org/kubernetes-contributor-summit-europe/) and the [schedule is live](https://kcseu2020.sched.com/) so register now and we’ll see you in Amsterdam! + +## Kubernetes Contributor Summit + +**Sunday, March 29, 2020** + +- Evening Contributor Celebration: +[ZuidPool](https://www.zuid-pool.nl/en/) +- Address: [Europaplein 22, 1078 GZ Amsterdam, Netherlands](https://www.google.com/search?q=KubeCon+Amsterdam+2020&ie=UTF-8&ibp=htl;events&rciv=evn&sa=X&ved=2ahUKEwiZoLvQ0dvnAhVST6wKHScBBZ8Q5bwDMAB6BAgSEAE#) +- Time: 18:00 - 21:00 + +**Monday, March 30, 2020** + +- All Day Contributor Summit: +- [Amsterdam RAI](https://www.rai.nl/en/) +- Address: [Europaplein 24, 1078 GZ Amsterdam, Netherlands](https://www.google.com/search?q=kubecon+amsterdam+2020&oq=kubecon+amste&aqs=chrome.0.35i39j69i57j0l4j69i61l2.3957j1j4&sourceid=chrome&ie=UTF-8&ibp=htl;events&rciv=evn&sa=X&ved=2ahUKEwiZoLvQ0dvnAhVST6wKHScBBZ8Q5bwDMAB6BAgSEAE#) +- Time: 09:00 - 17:00 (Breakfast at 08:00) + +![Contributor Summit](/images/blog/2020-02-18-Contributor-Summit-Amsterdam-Schedule-Announced/contribsummit.jpg) + +Hello everyone and Happy 2020! It’s hard to believe that KubeCon EU 2020 is less than six weeks away, and with that another contributor summit! This year we have the pleasure of being in Amsterdam in early spring, so be sure to pack some warmer clothing. This summit looks to be exciting with a lot of fantastic community-driven content. We received **26** submissions from the CFP. From that, the events team selected **12** sessions. Each of the sessions falls into one of four categories: + +* Community +* Contributor Improvement +* Sustainability +* In-depth Technical + +On top of the presentations, there will be a dedicated Docs Sprint as well as the New Contributor Workshop 101 and 201 Sessions. All told, we will have five separate rooms of content throughout the day on Monday. Please **[see the full schedule](https://kcseu2020.sched.com/)** to see what sessions you’d be interested in. We hope between the content provided and the inevitable hallway track, everyone has a fun and enriching experience. + +Speaking of fun, the social Sunday night should be a blast! We’re hosting this summit’s social close to the conference center, at [ZuidPool](https://www.zuid-pool.nl/en/). There will be games, bingo, and unconference sign-up throughout the evening. It should be a relaxed way to kick off the week. + +[Registration is open](https://events.linuxfoundation.org/kubernetes-contributor-summit-europe/)! Space is limited so it’s always a good idea to register early. + +If you have any questions, reach out to the [Amsterdam Team](https://github.com/kubernetes/community/tree/master/events/2020/03-contributor-summit#team) on Slack in the [#contributor-summit](https://kubernetes.slack.com/archives/C7J893413) channel. + +Hope to see you there! diff --git a/static/images/blog/2020-02-18-Contributor-Summit-Amsterdam-Schedule-Announced/contribsummit.jpg b/static/images/blog/2020-02-18-Contributor-Summit-Amsterdam-Schedule-Announced/contribsummit.jpg new file mode 100644 index 0000000000000000000000000000000000000000..62c83616a830f1435bce51f8025319821cd5717c GIT binary patch literal 246927 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 -
+

Yv?5ClgrF+}a&Q!LkC-~Dd>7$8u{hlh zP-iW<1jq#fqfXH1)mxHStyiL3)a}bsXHE$SQi1fN)U=GANayxX8tE}H-7^Ck>e*vS zAdTh3TAfh8*-gBF`nsJ(e6*6X+evJxL=MUO{`wy)`gO?zHjzW+)EvpQuFm z{YdFmDB&0FI$AD=koyQkpeRA)m|hI2|KDsy2_N-{YKA!E2FTD}?m8;Rl5GHkq?k*4<8 zeEIy=c6aq2W^^uQEo+fc&YyqW?Yk@xCboi-7PpaKFmw?U3 z1;*Bts4vcKCj#h@NAmqvEZ#i~r_&h-Kh#Sy%!xht z^p2+6Rpd6|LgY5!j?#d~DBR+dpn2{GZFHFUQZkOO!j=rVjF8@+#Rn>Mh)^p?ZXH@3 zP?V6bf>}~i*ylZtwBM9=T&TJ(a&pGaI*5SJvd z-t^2v2}_PMCm^(~;JB2jUieYR8o9WqS(3@W=L>Qi_<(CDHn{oo)knIU;+8{D+qPy` zrgaM3b;q8XXGm#s<-DMv(w>lq8~`O-aF9VMPB_j+w0QgK8x$r+b0cVs(Qop%RT;M0 zN&-u*?i_MJ_R++ajn)_M~0mIJo!B632d&RM0!n~&tY7ylQs-#@Yv=`&|@DmC~Q7zyu-09D_L>b zsMT7n)^WXU<6~)XCp!=`>P|*7uKoDesJ0e?-FeIM9PSFez8~%?PeXbb@uhVR+Os88 zs}0Sb{OWJokCnd5CAL!17TOS?Jj4>b@;E2o9nL;$oyW;{Sh(jQu$Ge%EAre^ttUIm!2@aF z0iH=1Hzs#R@gIIyHwHO$Mn2}mpExS;2sXc$BT9NJOHx0VvsW2jtw84H;?y$X$ zsqLjL6*@-J5wIyk+l@9pAtO?pxnN0JY$l7E+_EbctQaxv+lG-T*`?VR70UZ5ax-Ay zvdk#wE-3m?rxr#tkbqAF98%DCRKF>Xp;WAgOS(xnqg@KL`iE&%l+D96*%hQkkkE0F z1nyw4;7Wm5P(WEZ8&BZmbCZ<83)&9rrSQi%vF?vzE9YbKL)v}&3#fI$)Jyq<(rr$k z%ZFHUi)%!1{ByD;2Ap2!9Y1-MC3}>#f*aTdPM!_lUDa9gx>gAY*mUCWZ(^qOeyG^- zdM<5hU2)jVqL(f-cU*X>_zGJqNO5Ra7~~D9%15_tbX+&my!eR&_Zup=XZ3F5usUg1 zu_%?bK&94j+29H5m5f z8)o8uEV-&k39Lj@bClY){n+@17+CHTw17Z5qaq(Nw3;h!37Z6DI9UFF0)TV}qBo7- z(tfC#8c@YHT}F)#YG0IwlEVpg={{r9m9-5v*lD#b!;F%g0!Rf%4xQb~6qgvuBAQQM z%lA%K)eipfn&qi+(`wb4RN9MgM0RJCwj;@Tr68$nrN+_b#(9?-SWAcs;l!w5Cs)fE z1J~6J9L0_gjn+aXbjFWmb;5^mbwVvQH6EfsjC{*hJEf?GNs!AW=f=Vi!kbxIa=h^1 z87K!?(&MnkPb);^I%BP^qNn|GmuA{s8l*1aQ&qdghTEGC;eQRwtGpdb)YFAL77A2G z2_d8eZ9HIyj>iX$JTAMyf2*^+0G74I(GYEf?PMAwu?Kth-3&SjP`7&PC$AR;$3$+X z^vXQxu&A`RJfxw7Jcp*GfTeQbZCP(|H}yA&_@qpOG4~q-MG6)G zt0$6gd+vtR%2Y14)bE--QtPQ-zhPQ+TBSO(RB__uW+F!qvUa!-TUOwNEg&e9+^HZP z0NCUY+-$NXnmO27NpT!|D9!oMbo8gEapcuiPLV#VPN#fYnT+w1K#?T^YYjRGN=nwq zDJn*A3X(=jbF3IxHwy*hPX@{*)^2xcN~X@IyqPqgC66uU$=ay<5|pb0*Z`c5Y#)~$ zX_H7}nZ+-dqr?-wR^$qj-F@|QU(Qj|j*qnZC0k8H;pV`lRU%d+t%WTvx~UDSDQP1a zAw{-LnktC28ejO zG)Ui0-C92BJ&7GZ;RifCbz0_~dRn!~k*Tq1mAjIcM_o=7CZe$O$aJK*;A{=gI2M2c zun2IGoB^#b3}9?;7j~D5=6RWdJsz4ob>r!>9nmN>9;En$wWt*%E@`FI+>=p{HEZ%v z#8(!-DP)f^AwiRZ2_uf$(|j`z)d8qSIB`MdGnq_&T*#r4m$xxlK_-laM`YLtbLB+#HnT_a~g_YH-|z ztu791Q3<4shMox(X`LQK~=p1xN@;nK71 zW6AV_4_;K_FIT#CWcAjCTB+F1TNHTD7*$oQ3A@4=SW9VbB|Iz*flDjn1wlbL(_%HE zT~9j?WM7PBTz*ph~{)oX&1-GJlW;4n-NDUv@<% z+KqD7OAAi)w5HpT+i6Pixd;zF+PENO1IA8@b}UvT19i#ac+PNi*v);hf#-3)$8G*S z5PIOcYMnZ_sEt#cd75QPV$zvnKoVSOk0}yDLQdpwaeI8uGqGs|;aD10)P}k(F9wDN!KexP*u+cLFse0@fTTwE$znTmxlmgPk<+(Jr5^5R^M{!~B!B!EaD z42+h`9m|f}ajX9T3#rDDnnZG)hYAih4FIcS>}tFG)Pux@=SR7yRSRN#Dw9&} zYVVd>YN@^?q;T3?d;|h~u;P{q2qY|mdGy0iWn-K=ps!fEhM4f^6lwz$$jPi*bcM)j zBoM5=V{BU6Qo&MODmWx7zvaa~Q6*>$$44KRu(bDA>uoNN)l2#W=n>&WsC}Vtmnq>* zc`()z$!sM!LW)w_aH5V5?1B!Y*z|CKe89Z+Lz_C8Z>^iUAYq!E3680l6C7YR^Ld3e z))bT72hBrUfH*kEBaK`*LhaEHZHO*cBGw|M;NO!^dSF2Wh51`nM<3nXdHHI=xTO?P zwv$Vv+Z`^OP>$2Z6~d=nb15x0)YkmOAa-ymE+;?P*gj`acsiOsD&Rl2X`YEpgMRhi zsB01fP~NR3WSLI9hR}u;F&=Y@D&vOMqy9V%IB9nXIVWTZ2X${9zRvnrg4yK|C zgoN!*)TF3;0o(ZJL5y~p2?mE`dCPNQ4dnM%o5H+Um$yu;N=?C8lR%@=V9GM3p&`dq zmnS%;P|_EKjoX%Y9E<{a#x-o4ZmDTB6`||zPHp?wr60_i8YIS~xQS7ma$B2<-&;Ow z4lQJ1Wh-k51B|G4#&kLLaENZk%BlVsIxS!5tx~UDs}u^`>Vnh=iS_x>+Y6exV0s2GUARw zT8j54)s&6ogY0ABc}7<`uivp!@vIhNHIHW9!ltO9w=&#rvjr=5rYZ?#PzWxSwBuy9 zpaAFA)4-3aduyV0l08e7iLw$rpi7THF8)JwPh+PSEG~h&cBPoqx_dL-dZ;En@UFhB zw#;blqdS(clKOxE5S1+CooBvCUhxPw`>wJkc#nj&*%G(QbJ}^Z;?iqj$l|xHx+nxG z9~9*&igmXJB}Qwdm{Q|Qc`ml<+)lzuoFL#Gqj2nb=T?}-5M5w&rJDv^&`liB4KiNN z4j_Zvn?$>tqO}g3P_7X!vmS|Y{jRz_U8kk_YzU9Crx1m3=OgE< zT=vJ!eNat>@|~>w1*t6$qxH8ck)gi|uL%-KY4#TtEy{eM=F;O)+ggEfz@m8Ll>C9! zQOYGW+CKza@tuqV-U~t7aoF@kwAm@Vu8yd+2Fd#!_)rrH6&5`2J;*6T3ULb$ET|PI zvJ|bj+;^oVAw+8Cv&(1>@&l8t>4nR!o=KT#weY^m~mGS7Z3Su}f&gE~_Y)iH!gl(@582nAl0 z7Rq-dCy~FN4nXHtNiUS$PHC?7utVeGJ1CaM;j6XLDc7UDF1~F0rs1uzE|pHI(taKa zl^U$ejz@Azo7|+7xyykk=0IAquflK!Mr3*ho~vUA!ld&YWHeb<*Pe>$+5KU^sxT>3 z_msL5HEB|!nve7Ho~aa<8&=f1<45|^M&*Q{uXfT7?45JkoW~alZn{xj$%-jjB9Z_v zYqssse*$c!cz?M%kKyv}>b1{Irrmd)YAcZ-w%;sAf`tS-DmrkWm)~$LTkv)u1gB^@ z8|CI$hLJ$73rirFwfm9$=eig4r@}4GbkplMA5|jMp;(kClHG0$%7Zaq-|)&(r8KfQ zOM3<#a1cl-+OBa3;A~`=$Ed4ioX7x@^r|HuYxC+Ud4xLZ_aR6^6S-aTJ9ojy?$*hz zE1hPiKHIu9NAY!kQ6N{A?b}n0TzzdYguo?)r7ff&sU-vu9?0ylN()b^&Z=C_$d`y=z9ME=%q5rx}9!?SdCeca5q#CgZ}^)ABNdwr;0G< zQdaWR;qw)RfCm@^W3`ZP5W7*I9(=}+F~D`N$LfO@1+gO3yW&xxRv=tSafZ?*Qqu5g zd%a6SgUz8?Nc>!2W4Y0#!f4B!(mp(_76-#HXegV~fnV!|^V9yD`OOHg)k0#XELACC zZfy&Y>awM&4YZBe$VyV#;Bs}0VQ3}o0tHy_ z-nLQkEckPD$bBzpqS`#)L)Z@cpq(3~O;;^hwHBr^9rn_sNBG8^YBZ@O9$<)x8+@cZ z8VhtG#iXxlQk0URuEXvSxwlEEY!d$f4gD}ZUh2Ib-JK=695`*eP?tI8i;IrSLpj)g z7pSKRI8QwA2+-M?LlP4&JvR46VdEUhTL~a_v+S02=F+0{cCx!MbmLieEU$=7aSo-U zC6!>0E6d6@DLLSbrCr7bti_aNFg>Yd#Bk*D$+aoy!&F_9zRZy$%XP#)BFoxdZ6yf< zB_JgJ)(G#(AZv{A);+T^#BD@=D`Ugn*R=OadX;G^=%ykfC88SsEIZ~Yz5B403}Zju z&ZxxA7=E%ZYUYtH#`{4nxc-Dj7;L_kX2td}j zhLg&*be^@rw`o!-^nS3^U z?|07Rd^@f2n%KZ(bM437*nI+m-PD@R#%{amtKt)}=jPJen^uu%oI9-&$V;&RrH~tpTvX5V~upTe1(HS zbun5)d&-f!8NdVlbrAbBmXS&QHdAt`tV?R3N*zF09}kQibMLJG0Q!Msg_?NxMhr0a z>ecux+V<#=R8cPZm;pbB9nPCCD84GQI2%Sm1nxLJfG4p!8^W6TrD$s0@gUYhZBFU^H?(cmLTfc-TuX$6 zDRG)<$kE+E06CIW7wAzL9-Yb01KYNX!r0PW^JQ`pWxjxDr3kdGHm^H&{4#~PNu>R* z${G0CNr4#1EI3fiXBU(qVJ)i&QieiLBqZdE0Mv zK2#0IhjK65{3$0$>QHWPfQKR+2c=C?BgNSPwE*vwLPkggg)htGp6WRHYZE`fHI8RrLUhvClWzSC1L@_1Ay& z4xsd&o>whrqs)Yvj8^s(`7cOIY7yQ+C{nSsk;oX&bd6ZoxXc{&d-0-&74gFG=WVyO z^&9?c4Fac8JBVJ(_5s zX?&yseNkSWYusHJxR|X_s_wx{n_BthG|5Tj`f79W|IChTD?p=LzLXaZ3roT8KzT00FGL zSOJ-gVC0MVE!?cPPaEaPc=UtQtt;W-!GTop{Q{qCtK(`-%6>GMEKmD94f#=7kkBf1 zwP8zFB}5>gWPmjOD~sf25H|;pr?Nl5b70BBZn0WM^fxZPp!;xse63^1cDZr9npa8P zw@tpoQCX@#HmM1^gk-P&a+E2S!+|PVzUAd_UQ&HQ896VE5$UDT`K=eN#);bNZM~H! z@e9)Wk3)P-v3gwd;#KVXj;M*{?Kbq^th=b zEXwob8xv|bSL(ebu7T9%KurPKgs0$J)W%+HeW?MM<#HXA*hs<>=umA+KZv+M9*pRd zAOtmp?YZoPaRxHt0X6{cE0gXITSDqB?J}g(k{^8Gyp#txN>}sx{{Z8wgUR6p98q7b z-C>^hK>R+pOQ}?86=+mi%n7c?bxnLkV>BVKNH|gmLb%7aaoFmaJeiK$k-d&8{->$9PEtpO9>MRxGHXw=B>KCR>7<8P4Z!j2SDR?)%ZwtMJz zmcr6i*x1r!fJxYz{(Kevyu2ma_Qy$;ZrJy=yFKV}ej;<1vn;!m6%dz1mJpwY^{9YK zRoo2m&ej);Lyp4^RCm~cxcH6_;I(3b?iybQqkw3BJxcjaep=N&oZMkmh^v7TQr-Af zCkt)ej%-jamQmclO4HDMS168l!8*Ew4oHK4jtKWl8_WI(Y??)vJOY{`PFK8_ld{i zu8u~=7z0B{9eR`TCt>UqYs7DhM|@lK!sClLv=?f@gIkK)X~r_dqb(7o;a+o_(xk~j z$=TR?a0ac&$ck3~0BM?flV^X~a*(m@4%F+v!9% zaSx#51QJ4ANCc0?-`IoqqjOIvmbJT=9zDMgWYOY7uT?tVSXio4-%8lGei<-Ybs@%* z>q`%*MGDAJQY)Hs!Y~W z_CD?!*i>>8jFp78P)}{4I46(@l31MvjrEVGJKtOFNF6To3I6~|2jlFZego}0ORfDm zx-Clo0NWpK(95!6uAL|#DkF$03D{6_P~sFvJn#Bz9#0g>#R4X7-kWdrR%8DFNBBRB zzD&vOve>c-0PR56Q_!o!;lrl%&Wm*3pIMPIomsdl46x(XdD2w$II48-_;|6I3SQ)> zjDxjBK#)M-YDnWVgNUWh_+NnH_)Fa@T0GZmPg)!ghhFxWyi8H5-BGrx5UWkhw`9It zVw&P(pM{wfvr$nunrDPV*pATK14bAU={lNGZI2X)$GWxfVEm08}~$uTO%@gVeH#3_e{#-tv@zy`WHbq=Ips4fbb7cKWFOp|X0vn;>Ud zt5jZ+^;f9%+eV*IfaPM?eqvdY`V3}k0oHbWVrI0rmA&D4pJgw1=7blY zh`R07S-UEdqr+k))fIHt<24DiBrsIcl;T2g1EF!*^@GSp(~+eEe5)Z>pO|vpbwi+0 z{)b9(%<9FTbF{W48f3)PQqX*|RphJ?o%>GJ6O0~l@7qMjCWlyAp`oiOO(D^Mc2yBp@jbC(BMo0*N_Rrs+$XK?`Dk63CpeNbgHU z0nh{zYM^OwyvWK@7a)?g404cg0RB3t3JVfK3(0D+z8kt{2dMQX~X9Eh#aj+No=E$?hhTP$vR@Nw0trnHcMJP&(T`n6vyGfNocqsMS%p0 zl!eB&l4K?1p(rFinH!2$4hmP4_al%sklCG%@XIc>(a(Z1p>(bqbc^`zn?I8y!}4f$ z()!JI&e={ax|(Gv#_+?}y`XS7CnS1yA1P=c8VjDs#V6EvB}}GBtazL8 zRckuJgo-Rj#CO*r9%~4R5yLg*Y*5+P4(>9NJL6gpBsXQl z!R5L6220O2K3IZQHR7U_8`3XJGI?i*oIF;IB zv5`Q=Gk~D5>U9$m?s_dr$c;3p(^lFY4XxE~EF`4lD3ByCgy$fuJZDkpuPD_;@fg0J zcxb0ulP$Pa2{mXlDXd8IQMst)MPbzd3CfirLk9=$f#89yC~_GS4TF6vkDvHMO4qoy zi244C575K9!oC^}NPTmhi48%J52tI#3Ma599sR)MXeNP3uqx?Tj+b>UcgzPUavqfe zp)PekdYEELoA~JBVxmh{@Crgz8e8E@Q3&$eD#=oDsRK&d5&|5d{XyzPIz@wVOs7;7 z4SM6KOnIai36~N(W;`a;;?wtx<>z+oQ7J@q4@p-sb$#yX2bRPkA91`Pr^HIHS+&Wv zNr81rlt-U*sa~fRQdU$z{?RIw%vB>=?dPM)5={ok_y!?Vq>%uK zDRst)%Zc?X@OD_^Ja;;ioC=Lr#S=O|(i#)?410vy%j$*ORe5eVLi=5G=+GhWS`h25 zHd3WLr8c4wya1AgZBQo}lVpgUMbxyhaG#LdV|9KDl{cpr^`YWc$Bx@l8KYDkThr*3 zDQ&*(HS{6C^kql`YsefFJ+uWSLxMpj_@wihs1;0*x(S-s50^ix58C#`dWTCcI)b5z zH8s^~)c6D`JJM8#+;?hoxm+OtkO%Q#=a`2%JHX1ar8wljZto9t&5)IwrPo- zMsj0P+L1BxklXBsJfz1;lv3ixVoU}? zS)UHSDmcMwcjTsCn%T+gtShF*q{LONTayLp5MntY*)2<$hmhfAYTN@}VDzCNDL!Ez zn0Gzc*%3LwyHTyF4L(F~XW76F)OjS(v(H_CL#Z;VJu#_Dw^b5dzguZ7N2$e;9Z{sV z<7o*2VL&M)^1OEB9GvS$Qt4e~dWVDLV)!I2i^JR z*yLZyY0_Bq{+zz6`m}(#RHsU9`a=0N3XsTc!@)|Uu)Hn9pHT>GV{sz+8edFYjBjfP zn9+CKqeodP5~x>wUe>rOE=h?h9X@Z`Z74Y>;!6b%NK#K{6!3LQLBKnS1a8i-@uw{H zv#qaf@cdj)9`LWSc$qrm6&!<>`w{-8-$U|McCYcT%c#hHs<|^F6o*!&EEN#oNZNDA z?5y$FYogjfEqJu?ONlg)y!x1E{Zp%MtXb~eNmvyzT8_g`{6fpfDPe0;hEz|e?aB5j z0BM-O&H|=MT>k)BJEAQn@aq-FX;iAQXm=#I^I(X7Z^ETMw5}^;lFFV!2vQDK4o|rm z0FkT1n_Hnyp~8vTFq3-N9ZPytc=IYWx-?nr$XgrSVJMu^94J=dvv7C?9312fdxfUL zO{Rj{-AHMWAXU6PTy+?9qRZmvqf(;~=fpgm$C~Pp&_1j!UZRjOkdc$=(i%ZlI^NEA z?fl#IR;RA>vYBbODbh;}Q`C0sZSnzA&Z{1z0uVV*uP0ga08_yot z=Qio}YA0^WomA4!r>{l!ho^PwO`%~?Xg2(*2&YisH%W?;y~{ri3qecADpG<6J&xgl zfOJz`8-+9=p4kWADZ{AqV&B~^ty5}p7>^F8PjV!e8&Pqz0^g}wSUE_+SFB*|-suJl{SpNVCQ-Q=`gkc8Q?T;#3TdJba zy522QWIIt}GjL@wQYvw3n$sZ?2nQZm4lO|`$Dkk&$u+m|N@)uRHc#{QL_Uq$sq2Ir z&frqprd4gLPD|)AbDh9X;kfc-}2AN zOc83eV%Rrz+fA+4Bu#@@r_r0PG_eWyopBF6C6BpR^+ATzg(*rUYgb^DkgU83Uy|b^ zn?Q8_b@u&NMdKLp;Ya1M#m*+~hfbf5JCZ_$JAYLm(PP%*OKvQMINNPB+JQwir3I-7 zPhfuN1t~|J*#`q?*8LB<7ZhAh>UZJV^rcmLxo=sQ{Q?T?8|B6mDiumPnQ6&cTaYHH zc}XOdEwbWOf`=5Gke(`dHDOyDj;%Gyf>!D@E{650w{O+0rYiIbg%zrMk*3agDWSb9 z3vJ}DcLlOGk`kawPS8o#bkM&h5My?d4e+$FW^Od@Y=XmuekpHT`lV#vc6Cm1=>@rJ zR;ENmDAVb)UfkD`P?nU2Lxnjlj44V3w*^@`7ZMrck)zD9)K@<>p_x1qLgyI3H9*c;%a{uMVHemr3EqFQL^HFyJEzEv*G5KR<4G*KY$_SQ^2=ulZcG&U;DJYWM#Dk7e{4*zl6g zyV0v2hXL0i-wIsgQdHJRVfBR|>{#Tsq^Us($2bZL860!oE#Q&oxJuU+ynR1^qSx^M z02y{0bUC`2`5|{vI&pOL)W$b8x@qi91yN=IhZv9n=VO3lcfQkw0nRb511rO_a9jk$ z(csyo+hb>AWwe;8$4cD{YmWuTCu3W)jO|B1xN2D8!P}CQ^jp9~irN*poFO^(<6S%l zy2F#QXttqlmin*;6p_d4qp}YiKIS*{FbrJ|Ztw8@Z|k zBjq(jPnP?L^sREp1>BMBjvF8DsP|FVb>O%y#l>kO)a}Z~@ocwGkXjDS+x(_(o?fjp zJ8YFdE^LCNsJgAmC@BCW1Ml3E^hno22StZ>%CbEje%Y+}M(gBDp{26|J#yWY>X}+h zhBGH(+-)Qs#VAvofCtikx|Iz&yCRtP7|TD?*V#;bL|C@(OS~pnR6BC19_qANzA6&w z^?*_o`!2y#t$Bz5ec%cJ@BqNz9s*;FqqjDSd1GrDDb{;eP0ioeWCrPNtJDsrT{gW2 z%A`+`Q+lS;sG9+$sS%n>h$cduNC`qvKs&b%+-egvn9kRKkFuT-B6c_$q7C+6My|)M zdid%)FfQRrthXr<8m7stDl?3r60eAa{{Y1?FQ8 zpuec4Si14nOVUJVEM(oxR_4}TZkHTIaZgjJ`;r67j#Ra&&4>psl@Ym0BN^7F4ky~D zYeK;BzY=a1JKV~$IRFpgE7nZ=FQ#_VC{~OV$8%~?DqEN@$Z!r^T9165z+fa1#&zr% z*zn`GM0|cfHS=a`Iduw*!p3W>y@Z{MfMbdY1`OyFm#9mf9vA;G_OY3mm~ z8={b*t%@8@l3j9R1ktK+!I4I(u*T%K6uFJ9EeQnqOG-%d6s)L~D_s1+-+7%EV~gdq z7EQ1}&!QB_@sHFlym^*ve}|^CEkZp_+Dvej`FX<8Bk(Dg%0O07B z&)3pJSWM&>p_WNr(N+y4Nzs;jjxksdK?&)>az zxFj<@n!GqG5QLgsRW%8+(`gG!4D+!GAoj+2Rt8SA823IVG@ch5;v{{c!JL0SsNwvX z78M_>9dN0CJY&=D+Fb_LEX9pfhKHMI84abZC43!)OCaMQd+4Cx#**W@&tP$BA*Aub zB7Z8MOl&@w(Rz0p)V1yU1j@9z^5s8DhRZ8cZ8FLdl_>yaC2o_0#&PoECE>$jliKFD z)ISCD{>MzF?j=!aZvu;fl~Nwvj1;(}k&<`-Ee)$b-O%rGU?n_Yxxu~H(_ad`9_h6k zqLdb{`1RP=ur&1@<>sUk_wQ?+<+Cx&NlPFx$kqOJ9J&p#4Uy< z!5!US?eXjQDj(vymSOcuu_{eYfm(W^>#|cI5O;d6c~50x(!YGK#P^6!Sa6VzXU@|%@wHw{tJ;76F{E@QEPC)kuFu6f4bb+Apj zu2|=gLNE2R`T5bygQ|7Q&WdOjCsXCSPHojijN;U_sh1Q2Qu^LthFftviBMK|Z3RH3 z%ZoYcrskJFQ@+2=lvk;JKcQA`y0=rR%BlYVH|{u(x@E;_Z7P0RJA+6{RFov8vNEL; z!j29I&?aV=9noKAcp8X9Zw6gWW2Al~D6(VEEnAftBAp_mA=1iQj^c-ww=gg^s~d(6 za&R+^4>TfOHfoRI)fM5ngBC{)bpk$pK5Fpw=cxCEn)BBM8jhtU52g32tTi4a#KqhT zh)kwjLYzvQJ4jnTU>Nl7*FmYFptRb^(CtJ!l+}0milM``ro8-GQY#Qw_LS)D$98M2 zG#PnFL&kXl&B{w@%0MX!AOpXK^8h<13_Vcl^Xif6UFmPwkmpp?fd(VB)%+|)tx;Hj z%kq+!@V`-Y1+WHEkgdE09EUzbBNk4`_%Y?lc9sq4BkNNX$i4&VQjH=wxa-%Fc*Zj$b7hQGia!vB7au|{9;)=Sr)smQA8g!mVF^;{RHmD4sF76Ur6K2)kd~5g zPzuxu^3F***qSiNnJ0D4vCfs+0O3UBbUvv|O$yqtF#V@pZY<{{KKhcTCNz`h78`X1 zNG_Ixg(G(=0Vf2FWja+3c5!Zk*rCO@4K zn5f#NJgx@SwiU<)Ua~WTtk>qq*4PWCJ{6Asc&>k+RY592q|AMYa!lBbDM)4V*+%pO z__p^M?}OVq+ys&8<#0}D4mx;NKf^usXj`-GG~DnLU5M2_vdfU$mgH9>xV5yTC^*^N zpD-m&C=R)PXOkv%Y--8&=Lz^Jva*Z8Fr_*gWX@42gTUL}JC?B$QjAKi~*u;23v#dzheRQe^+>IJn;q|b$J zwj=yz2%7Rd>5N=k+g?BMVYb6qRLdUCnuO%yS@KtXla70QwL0_jy> zr(Gp#>bRU+cMZtMTz00ZN63l0d2pnGu)Mr1kL)48o&~Qx0(m7e#T-r~fHxlfP&36v z@a@yr7&HoW_RYmi>ce6%jU}evODm+pL3KW6c7&<3g{*AIvmEUK3spoFO|6P0c?+g{^Ggl%Ce*L79rKP{P z0G)v0DmYH;4oDrxXCr%5K-UPyr8ej-ziiK|buMk)7If=&lWVG^^jdrVQr=LN6%8P) z0#cH<6Oui(5=aDuWNmAmPEI{TwIJCx#3=QPTA5dnrnahOKDfi~LqbVDN&`-B1)!`S zF$&~*iT285vOV@)OK&3)n9=Ub>#+qQ=v-flv@Xh2SKMtAByEu`gdaG5_5!w z;Q>k@;CAI&*kQKru>b8hvG(IbL3mVq$;57Lc^{Ew!mf7g&oW!DQIku zUQ|f;)!P9@ND4#W9Nj3T+c({}Zcym-yIwn%`*WqjrASn!{LvxgaHRz2Ar0^n30d_O z1a8#?-pV9e1GPn$Z`g5-R-)5NeWKxEl@lSs`v_9-pilx+oZw>^C*97$H2^6_X}5u; z#-P-rDnoTzOfbt0q%Cb6E!72_js_f80Dv%0eBuH0D*pf!!ZPY0ZnfyO9u%Ic(c;`L zDh)lSOVYf?x2PqwmHrMl9DsI@#f*FC9LJH4;?2s?@a8w|ZDhuWRbhI`cG~wnwwUuT z81v<-p5mL?Yo-d^JJuLVUH~fq1Z22z0GL2$znt#%YZ3;^*#QkdTU~x*@#Khy$S%85 zul^lsQE5GBwx!HrGUFx3gN-;26codQ2LyYcnC-5m!bb{>TfNtwvGK5nNC{}{r(P>Q z0;x97l|^OrL6H&kwANIn!Armp*eX#2J^B1Z>JhefxBK<-B>rjLBr=wDmpeT0%AgRFDB2;XvS^5Ph|uHZgRDOFQ%ne-AOS#36HA zweD?3pRho#V-l(+@)0CtDAKrfPBUsT6h5K2#O7Rp#D`mXw8)Z)D{Ynj0;e1FtbzML4C6Q% z#i%C=jqVHZXX>IT+N# z{ThM}R#b!{ZGWrM?2E0NSu)*=L~AkG8;Th(aJ3Q#0Ih0KBag(Ka5NMzGB}r;S>eU5 zEgT^K0EyfFRnJkQvbG|YAvKmC2v?q_+yIu`R(7lXqNZ=6!XQ5+p<*>md{fpP%bN?oft}_+;l*;r6MvNLL^hlhB&oW<@!=y-KNFbi|1vYAhdzXUjsi zg$y0fEN<=wajge=fVV@aQqPkr31ya9;twt)?oQnWd=TTUohyrN^(GB0$aYL96&5KJ z`L7|t=djC-wdI`UDF9^gvpEL`c68!bZaGEd;^0k)*&u0S#dqK1(|(H2(mHw2&ZEYi za^DidZVI%9RAkAyS%QX8ccF$*)=5TE%CY8cD^gTPr(ArKK8xpJQT{ggz1!eY3y>r;O{g#DAF!O5i+M&UR$3cVEVh zCc6Uda@MR{(ppQ7m^E}%7TYOGmQsM6?cK(37mV?u-?$>_WU+k%wLg?vWg3g+%CwkC z*gU1lx`HPwC@M%POk}o|l&A2iNhg3i>m|q4O(d;=$7wHh4`dPQ_47dLRUS>_M57{! z0exnPOTh0JkZmNlHpkP^7bfys1ZW$Vn*)(TskRrN;WK*FRJAG*KZ-{3Z0| z>Qx<@?UhA$sCP9gNuK2bwKhBmu~r%=YHMe4K5i7I+750TmPklGq~uNFZfu4(02|+R zy^rB+F^L;x-L^!y9w21(cd2wsW2Ur5}LQ9Bh{2{8B(*g zJSdGOvT3hTru0{tG4ZIh7eBG+jh!#>rBbkNTdftF<+ak}Lyz`cSPn>aQPq`)&+V4rkhca(u|5a-vzZa zhti-<*9wx5e_=oz>cRcTSyf+^#^F)O-7~#vO}_Ou)~(Hq(<*V-AVGEHHs9eTWeFi8 z=bU%;&WmH%@#!deTQp9xDI9K!tZUQ7)wNKq)KbMNLAT^iknEf(Otk_s)D*Lf9gKwg zV4QacNbXTgc7f^P25NVERr%Fii zhtTVwBTy@c29d(=@f8ECJw&jpl4$L! zYAzx+8dHgeNh;H=&C=P=Tau!H&gPjil2W`ZgyW1Jeb4UJbT9RSwXz{TSp=qQU!+hf zsg`MXTxgdyJ+U%8N5WRa;U1!r;#K!+$QTM3IqooZs_@q^wfqpV7$}D{?vL>36lCxV0bg?Ech{= ziC?%{ZK-K>Arcs+qC!H^^9f!QrE|zB2e!K31jB3*YjEA)mrvbcc*a+p@Yv0U{$(1x z5?QYF`=S(gS$($V)f*FLIPeVOgc|AdXtRTJ_gomRCg(4$K3VEftPWJ*-=EhqaMqCOzaJ1>cYg}k2eY%@_boL0@ z;&!70!2tTy!5SWlMW^45@3y-C6H)wFjZM37E&&TgZ!PkVzvaN%^N zTvGb$;YKA6s|l#JX;dWCqeVje#W48uABvz!DoUJ6NZL-~g&dA_25vCO#&k#J>`|CG z1_|3I*Wjq-MuAs-prp}flB9!=DMaAl{I$SGg)>c-mE1{}0Tdh*BImVh6xc>w$}H%N zZozg#B`F8aR^YUus+3U$XxIpEE8QS8K5wj@n>0-ASdiyt2@3uQgH} z+)|Y(wwp=)r6)KU_`V}HQEYL-O|Fh_3X2)863sw!UxFjqo*$x3@cCz2eO-kbRLV6@ zZDs0oNn2x=UTC!2PHg~>Ed&w}tZo>|0O!$hyf5b`&+M~hUA4Z3#-%lD z&zV-IQl^O!Dbi){D}tni{4-mC`>+x~PqL0iPI6p0Y?dcOTVCD5Z?rlm1JH^p6a1n# zOq+h=wy*dW%zC|Zog9G<+AM=WpP%=n;POwT`Z6pAnD73sOyd3a& zDFhpZj&a@}tCL?O4ot_yB6Axa&D_@ecRi5Op-hP;qZHe6Dh}0Nkf}+Ex7#tKMs2k% zepo3B4*t+dBoLJWgMqF6Ph_J>+xA>!*s(e@Lv?R_BHFO-ijlgiZXs;bQe1%zN-0y) z5(103;FPo!jz6@t~G=wE-BqZ~=ah~Tr^ueH%J!&*cy!8&B z(Rx=%vTZ6u8IY4T`W>Bx-2EP{RW{8 zh)%dv_5I>l)XxJK*=!|_)-=7 zURm7PKIJ3lsk8tnEXnN1OS+<$hMJrP`dc;)VfEH(6>7w2wAw933$hpyP?C_K_neT* zRO*rlLQ0ex+l{K@A3wrdofu$wjNRL6_@jRxt?z50@Q)mq!yH|tKE+eGu1CJdba}7Z zaH_p*=rko%CQ7L;vl1O}lm;4%>oU~hQqw5(GM&rVlpqho>dLnhp@D%OCOdH>vet^+ zl22X9>wKy+a$S>_G6}aG&q1*47atZesJ4ygTZ3y{)EO-|Ra`kVCg&-+v1Tp6lAnbj z5|t@ng$>EZa7Kh=5*KI#m8>(E<~8BImyd z(G^b?Bz@e576I6$Cu5k#6hQ|WCrQ|_WNkYGyI)0KLyfe+^2_Fr;Do+CI`=^9b=_&T zZNa%%hem}Z3thw*O59tHrCXXUl9eNB2R-w_?afWb$Hp2UXcx_OLhG65`?41S#hayC z?58Uq&q`fNgHBaSZ7yRoT4b=NkW_~fq=ltCs1g9$IX#A%<5(?3W4y&HUImbDyRWTK zdih$R(qu7NsWH;4qMt_ixE8F22f-O{qi}jSEh|1zC9>0}(sBqvPVI9shcLJvEqY&> z1K13ri39iC_1%2b@fp;|_n znp)dER}bRZEy$Q?XcgOqF{j9ZTIh#|mTC^V%w{gi-7Z6nq$$9{-lsZB0pOA5xyQbB zuEDEARvVlHY_FldAt}~RSUPzc727_CZ#i$>3{IsY6QW~E33N5&sj{Gj`Q=IhCvFDK zz$+kA;(};d{kWV(ZfdC$;P1l7nXs7v;(+VbMlVX`zfH9%EU`qr>b9#$lQuJt)EkQe z40Jb?p$+q}gf>b}3u*I6^8<%&xn`ZMdNGIt>*K9-`LCAs==684`n)PqU1pl=zEnW& z;IOU0p2OJWaxvKPu7U=+%ng&O^4}1X%6sL<;1YZBYw7LLVszuJR*TUuOWBm&a4D)v zrAdOzE}$i_wYQZG=wGCzD-JJl^<(yRkt9Yb4wn(xdShidc#LzH4S{5H#^%)Rc4tMY z{Udc1TgJ<>XwO1ouKhNjPl~sb71SXy)hFVE&aZKBdbTA+Zg58#&oMav0Cn=4?5cZo zxJDtiiuG`+mrw0mHoxKuxfL}Ur9YY?mfZ5wy-UH| zrC?yGav$Y2Sf6a&EkoMfD6+Y=pJ zm5rN`CPVk!4lP+950+2cwjHSLO31k@mi#I^imJr5U-(H=qp1P1mtaSdG%LK$TaYN10P)Z(1=Vp>Zatzqw5yCoTqD30~&N+5tQOc8M|%Jh+zb3b!*W z?BR`x{*njf^$2s+ewW(!_ePi0r`PrkdPL>1Pln5=Q*#?q+}M&%6rj*TJz!^Q{YQii zZ3xL4mmcy1sYCoX^y=NZI=f}i>TOJy5}`HN@{vwhORsH=>d@O|NAVS*KKVHS4tcHd zd5zK)_^)Fn4tbzE{#$qH_^l`vHlFKcze8g73x^`76}VOUD_d5DD5S-FC0Hn07N(S> zD+L8B9>ZCK6f=Og4sV$KI`%v-qzdsFNvZU^Av1(|%E3HAO(xk zDhZzbWtwbB8xY%WF&$;HuQaJdkX3}>@G=g#r(?z(YD%(io2BTjo>xZQP~Mh`B-I~f zRl1V~yE^wkxao?F`jZ?x6}fH53@L`)S{hrZSE=kRB>aM~dE;F_fKpy4jYR^mN2hxb8bEJ=AWe7HHxu zE1Xnr`E0%M7Ni?Bm~xb-$C&G7#53pxAt6g`ODhe4kdmcqoiVt$3fX!D^TgP-vEHN7 zf&$ZO&O@nywegzQd*yx9y~NZ8aqjB;O$cPNJ~lxTewI{N8wtOoM>+l@vN^8 zbAvIpv~fggcYU}X)^}WPG$wP^M=3pAy?St|ja#)#Is{5|NX$rCn5jysdbTCjck(lW zq5?+14&#Han;K?kio7Yd%h8B-}2_EvckMd3#W% zn=KN6J8cJG8Tk%=gN;4vG^=nRTCjG zrK!LRsZv&=pHTzfZ#yIpbeAP^PWSX(gc(pb9C>y&t*Cta+J^M*k!tl{uJ0ugs3&yV6z(AQ6nKRf@)s&38q6TCGm zL{6%IC#1^;%vENccG2syODb?gQ|e%hWR0ar!6aY+qMV*PoedX@ME5nWZEEBEg`t!E zJosXKjd$JV_WBeN@cm)aZkw5x>$Nmf?Zy)8)i+Y0lN|^^Eh)l52}+i=Qm%X8%#j{VN=ppE z6&ImLr_5oX18Z%hm!ElQQBVmf2uK9yk|6Cd#&wlrV}3-f5jM$2e-YjpdI@|{BqrRh zPPZ=k46bu%O!*G9e67kZEr~fU1mu-@Y70m??V)0HE;ka0^4OFp^TqW!Oy4yG!d3c4%N=fM>8q1Gs~wE4=y&Y zH-;{fb&|sARR$#*@aghtk(v_I2Bk-q^04BIt4icFr1O>jA^B&FX^)6Uy$%#lg3JST zAHCb%Qx3RwKIp1m^y_xLP&MlH5^xxd(@(U@(0yAR4F^;dqyx1|At4}h-&zqcNgl8^ zDQ0CsjK<=$op4;jL+?_@0$4%m! zF1F&^Qc%MpoidpoOHP*1rsFLnpoe`5aVb$Gjmqvo#&coEocWQRzAIi#oQ!se<>gjUL*r6$IRvn~;BI}lUpJGc3X-{z76feB7I!kY}r zNOW7*eyh5JGANofPuGn*(qyV$)jMt5vgNX2PiB`LvnoAL%TrEGksW2VI=43|L*e}( zB$NVD6|`>}*~f{(G3I~5@hf@{M0`Q@Wy-D8?ZDuuIl0G#hhKHqyAm>l zl#_vwkbRChJcRuGXvl4nw_@;2*%{_~K>Ssr@TJzvo}ATQ-s(&4J2up*h>EGU(2!!r z_)wtp-~#T{h5B4r2}n^&lySzSBu@yFr$x@>#U?I8p>U(YKs(o|75@Mc-Ab2rUhr<{ z-5rA=CXG*_Q(k%uh6Af@rO9!Vzk1TzmAHa%7qb`{113kZn~z1u+y$YDj}y+Us|@Kt z{Ym_lVCn_L_w%h*qjd!T05s#){vsSUJkrArZrX$7UhYI*FroJ9})pWDc%3^K%j@GqQwpm>|g7qbHlG_PELVht#N^R7JahBbl)7YKBaT*fD~>#l z?lw*yJ^Fu6>77!OON!#gJDvTJkL^;uShx25imzH zV`YE`$!%mzXTp+afL*A2AD8&Qk_L4D0K=?~qgXY|zC_n)pu6z2c)_Hs)MSkLg-TMA z8)+wMO8FTl`zKM!@kV1z*lN#TZr?N}7lTQej_iw}!+rbwkZlqjqty4X;+c7c5DFFv z1aNSn!T02M*5DwET=4~_yDJmY`+gTu`f+@-68L7DRHxf-)X`0!@Py6J5H+( zwymC|;YV>v1Yn$2ESlRwXdGN+7z3s;p(whQI4|?Os_GC052*_ zgq~Xo1eE^#jVCsTq$tKioHe-7P=2f4Qe|}pp-i^Sbx@nDN?ksmPK*!^UQkL##DzGX zLQpyMqzrMVA9jjok*m|it8L+V_syeNgD|7wVARtA$67vMDh(k@{5{AnD0*|9qzvl| zCKk45IDe~^rxVMV(0VSOFgmen*E(@jq1#s!YKoX(#WCSL<8Fd5+lX39P^@JmC?N7Z z`PP&mG@)e%uDL`$n6CS!*>tN~w{2btlTC=*aw|6NCIM-ONC(JDosg8cSp^^{6_t~d zp4zmHM3qP+3PwuB#E3TJx8So;az#u#@%2SSdNjI&ow- z74@*LCsmTFkB$DNRxj&fbeP6p^L@6AGw~&)E%YEMA<~2e2LhCr6dgl~P5{RTaUpUCV7Y-2jj$R4CrMCnJ4iP8Qx^oO_&qAQCh^aK3$Oeah2StjkIF-J%1w)MJda(WqF zhge|+LQNXBlN~q(N?2g|irRU|GiH#>rS(@nI8`&lApTmiXt~P_^xTaLyi9cpDxI8;L6gcTYe!U)6nuF z(5`w-LXxLea(?xaQjC2_82RX2%y9%xdq%>K;uNr*B+oIoa(aI~za%K}A!E_{IR@CN z+gIyXJzgzIIYc&tZ^lvyLV}7(M&dzE(}Ul*JY`3fB<&KuBEk<^{S~sn*j!i~91mn^ zv3i9P$ERD7=n@PsCYl%Vk2Sm@$qFyMxf$g<))G<=As_>hp)xJ+I=iDF0yw~Go7$a6 z{&aO7T)C9g(P|2Yre(oPo@-muw3Il~_}v~5*dYl@R8o|Wo)Q4(-zVv+g1_#73atJi z`nOB5Yu1HksVPjvjJI2Li0v0&c}HV`DMxO0ZRCNKbE$_0izsKf>J*4qKZl!##g{=- zCiv;%Y#XsprQ1zzRnTQPrJ$0TNG*>g4mN;Rp7{wOAc77-%wt|0)3MoUHyFzkqj;wc z)eF9B6>gDMlSrvk%{F}&OD_ge1~w%@NK$dalYlmn!2{>5c;#fQ^B8OuisnBaO%EG| zVf;T)>9>Vu)4uP^zxkb3{&hN<8YLwUL6s&mtxS{g4+S4BvK?)-sX4=klg83ZEDH#h zxVgdodv{iw{{Y<$eNXDW^LgFVHI+k0^wiEatb@8|as|f)J!iRD};5<{Y zk8EUbx8}Kwtht$%VqSGxZI62`eJpJgWEi!S7-#`uJ^-A!)9 zMJ6mK6uhZJ$n)F?&PtM#`#g~xTH5l#WxD~_ozKhlTTjSwYhB!Kf1Szg(R{k`U(*PE z59{seZqaHo=hCA{X%LqCp?eZqLxr`RWT_!QXZE}3c^Vi&9Y8<7;;0TMbRqbPeaR{$ zI@H%vSXo+C6(Fz6JgEab4C6UI{@m(bU`_I}x?x$zJkQ*spF zm>g2eqt&}=R6*>LI2yDyyN-&;+*Oayi2iEUb?t8xHxw@Sq z%QGr-A=7D8*J8zx>v0@ZYT_`gM6){Zo-)QCzK?B4s?DNVU!2B zX)7l`1VJf@hf_%Bts`B-Pp$OIjZ?Slmjv3|?mC)_rl9eDQHzGjPUVuYQnKP#v?FTB zAFv7ZjE_1Tev6)ljE8sjl>q4AIo0q=$`g~ z!(miznbYhU?^D>nC)1%dP<_a6I+<$oqNKPIm(&t4l7JLO>|_znyL?vTw$4MVW8Y(2 zFEGty&Ssb^R;KgYRXYCw{7F|Ut5nNtsuX&S%R@w&;@yiCG-#A6o2#Zj0LsgyFC>*WfoM-XwH=%EgP277P67)90Y)(IaXDx@Zuh4 zn07$;wm>oYEZlxdV{&z=&Y;lf9W;{k6Sa#orctE9wVPT| zN)5$uvY0W^B; zNiF&6azl!B5!O!Dq?XxjVD?aF3cx8NE5umcak!3ef8BJR3oM!>Xx_I2^Q1WH$5rWu z@T%SxZNG3^v1Qfb#GNv}!a+=?rXpvOqFr<0$Pv&-CwWV`00Dw9hL@K*uWk_jCpeHd z%LceN-5IT(n%kD|QWeyM*58>`YO`0kCC*xs+(_XJ%aFM3?Hi;zHmh@qP})Y^>-)e z0oDZmCleg)?@u(k2z(zVT@I?(#s2C&Zp)@nubO?eTcky^dXGeMpE}pMP)K1j;*Yt9 zF&nn3Jc59b{x_lA6_SN32IJ&2A%aNOenuQ~ zdu_T-OljtGt3yHf*#qb<&tGH~Jcs_H1Wj(w zaqqAIpVEhQZW!tWOB+M<#% zoE5)1t0H>!G??ixWzWmqK zN%})kYSHV8*L~A#v1#zp_Kh{Qvf*oUD++ykl&%0|Ecv5wNl5LGK%O@&nKAic+amt} zr?H!Xk*g*$4OrW^=!)H2>U|#9fby%B1=&iCGM@B@XGpzVkPsywx$~p#*sn-Q!&`R( zM{U{T+XJ5AppT;NXP7}5^MiwH*b6?&ud{4Tux`4Q5@2{@ks56}LRwN1mLw&a2yml0 zAfWBXIp;d;T6CS)nR<0ldEi_D1D-_Pe|Q96%&KMM1!hS5s6 zrLIUOsXl=nhYP_7^Awg+OKC}7cp*UGtM-W2t|z8FHTwQ5jqw`u%Yn7ZsejyywI))N zb5$H_vgeyuiWa1%Leh|s6adE5r6@=P0{{R$wR76nKU=v7MoS}DVrkg)M2>)Xa<%$_ zP^hl`xtXD}ON6O$r~&jwpHNyz`?VJU*fxT8q$y+(fS&r}ynn_r{4he?D7Bd#q@BoM z??aM$bncIb6|)288qzrKp&ebYA=@+PqMsjaKD|Mw*Ws$4$HT{v&<;m%6%wtEw&2{N zO0koIcyz9{3%U@yR?SL^tc+mA)4E zaq@$uJ9PNn1X{g%lWM|dY^GiLZvj?K~h>zqiS}XgoN(= zTIYs5j(7IjFQ>BZXUStD{`8L1+Kn6UvZr>X_h0EG`jtN4tvvy{ld39945eyi2`Wfh zcN}l>)U@sS5;LCNE=D6>)|ojUvf!|@pNS*e8K%41&3F22mtVbhuFk8LDHj`0KxPwE z_9aB5H4W0s0bzi$K~{FG?!m@Rc_TUwJT^E~jjx@pDZFbU2i`mDZa@InzR2NRv})cY zuX;r5I+a*zJW5X5&2B*%UO*`yFe2$jE666tK&*QYh(jCN zz#KIfJL6UD-9(}ECgthhh?@qVbVY5~D>ZiFY^gL$t|57EYwYD)N|LWg3Riyl;8y&o zvN7ITNTKvWM};mnTx^gH&*-t@=b^OTk=3o3@DlS5PgP1tZP!v%i0!=FY^P{QBeRDp z@1JZPTZ1Q?5O`7XSd0?})qgnoA%91&N$I-XiseGI98@_m;i8QoB2jtJgdK%IjO|WO z1wRKJx69Px;z1YLM(%5J)U-M?XIu1iNUQZ8uU1r=$H&Hb zhUw{3DMVQ4Y1E_;zci@0pmVhC^x&Nk{bZhtnS4eeP8<9y^HwLt&5urpN$KsAZBWdw zvZ=`tYP1KNj~S=NTX-Hxb;bE;Q;Xb_z&Xzvp@!|n8b7x{DQAF0Cflxc2H%wcAGBy| zYF)`!b#1hV7PL3yhTK6eoVtbXIM0*m8+kN15OoE2nAdtu(BI-vqF+^6u_e|h)mn#C z6I$6;I-_ChxPpzG2;_OEaS=t zZg1ao**4>IsC4Rl%E@Ap{NJZDOL=Hk*QACJ;*vvqN%K~nsRtNIN|vq()si=Tx}jl{ zQ#bzrN-KDh>YvzEZkJGPccf5aTh{l*;iuB4!dRw~^puv)q4cFk(M)l#YOD|Uc}-jond$jJ?>mj>ca+zgd>$m5am zSbo))TEGkgmD%_!{>zE1vh|a7*d)F&uVH*!w)M|Yqg>PkrlRc?!&;|&42ReQF8OH$ z{sp!`$;jMCxzQdE1M#MF96<+tx)e9{6pYBlY>~8rHW%0URW5c??h4`*w6hgbokA2? zXeBAm6P=^?pP9+`*Hu6Y3yAolC1&`zdR;E1WeUP-R8~Be9%&I!hUYMcM3#_Nqq843NMSn2tJ;@2;+c_TObahz zz4K$DthVP=>DKk8TaOaAPr8_G2#ZvuR#hF9Eh_~MJl4`wP>>P=N=NN*bD7JCWPOq- z_Z$6HF!+;Whe2u7I3Vrw9|aMeS*l$XsrBl-_h-~3xTjv3IqxyoT~`~FRg$b{B=g%v z2DT;$+BR8^mD5ONd9(ZhS~wj>O>d@RuT|*9kzBUcs0x=;fb!{*(3r#F+Dpzf=v!-A zl(JTl>sHc2hdSpS1EZ5jmvPXG<#s-6WP{D}#U7y72zySy4ei$%6*@f_L8H|pwN6A= z*6h!RKy59fE~xKyL21ZRkEo3t#++P0*PC$PVPA(ui!m9QCDDQ!Km)G|-`GA9D_tj! z)z#BmV&ttzX$WpaO0q%|QXc+Z;DXxuBz_^0gN<|fPnX1F(w9dBb{ zjNDj+vlbSL^!5Hy<~&OxY+T7*j~F4w{X*!Gf4{{+JX7^8{{Rt}m9}m5!>l_ZBw9-b zI-GIU$S=H7(|gmD0p=x3><&^h+-QblMd9R=DR`?S^iX8kS@^+@ji8rMp;mq$ncIp@ zz9TP)mNlPB>8%Om?WV^}N8Vva2Oo@+{iUd>N9c8j;n?oV$#z_v71DUVOE9sUg9+Si zx8kdfCAm*Rnub~PSyBg>Lr76h-a!RJDg6k~ZFWU)1gW1uZ#Jx+rcz}{YCF*8d6daW zl_*7Iu_XnSmAq1*+EctJt7*UoPLkiF6((%Uy0=<%q3IM#MCW5Enanf{f{!7kC(Qo1 z1v&{rJ!Kn;akn9k{Z))0I@~QoE!i@D*o>4+ayo`km7&EUL>%P-N#t(H2cL7u(ki|e z(q92RGpAI#b5S+fvLL_w<8=s+Oj=z=Qo|mSw53De@SJin-;D<}50lo^R5LN7L%A#0 zZG#Fe-Edl!h)vY17A49nG{v~t4?7XZlQD&H?6%IuB>RKdfv!>RlM66BA4|FHyQm_I z#IOu|YHt*$oi3M5oqEJ_kfiw)+KXzC>Y_B^aiuIMy5<|)wTAQSSyG2RwbMyFaKvSh z(?=z7O^MP-7{R$$52+WuB8$`euCnb$4A?ZvbeZNWoEJlFtw?Q1R|-m%fI%FCjA&>x zak6%TR=el=a*US~A}>_2kOx}Z>b@`1D0Q34WSer4PBZFNs74cR$Xj5;I0bG3kP_Qq zaHF(g1b}izOUTHN7Be)anm?2~`zkT9B+HaT5Vs$v{ClFE+hwA)S+V*{YrS8-?zO!g z6*;ixK7^^HsR?^)C|=aGly3DX0F;19$<{U;)8rE~wrSullRqCD4kpAmc;v673-I4y zd`PA$+^a!^g_f8@E-Xh4gM_%T!Il zMTON?TuwcXLDkKIB0Yba8PZ5kr4K8A$?0XsU@=a1@V=4akd2L!tMQ%VW$|G5A3sbAU6RJM*j@ypZ`v`)}&3 zjxy3mRN-P?jMOgn>cx=FT5sG25xHJmbfn`47$<-azaL#Z6aN5z%<6w7Tbbz5*;syw zc(0-K)2sAn>QY-Ymz1hqRcUCv+iW~MwW(lt2+CAPzSFG?yn#GsAQlQajHJXJYgLbt~T;DZ0bn86&RgYZFKzg$$lu=T3+k3kz~Emr5rW>=K9lH$MO$BlE@ zIbgM|1BzOhxQ>=bZ%DIK>GZo(p)jV|^B=zCM`T5)ssQt4Qyty8NmD!2u#|8CPI$&Z z=R${v`hp?R`E4x*=|DOk);g`l)cTC6jQJ>LmX-lYDI1cogl_06hJVpzgXd>gc8XZ;s651*t6OezhbO_0Wn$&~x zpS1-=>K6?%TwFUP4dq2aNkY?wgW@2{wh5NRx0zMmMT# zi1@~1z}@$)oM9- z<>$)})9yPSh(8sn4U51ypbSODsXE!Z~te}z)|$<^66>?%7_OHRtBQ{z(6A+UG4%NxT*!cQwo78?Y9 z$`hVOtC82ba!a}BqTN12B1n1o&ODs`61pPzk2q$reD@X1hITl#%nZoK<6 zN;P_OPbifXhG~+^U}v&|)`FgRIr(aAH*~Cz?;?MRXih!VPLa%RO1!&{%d}l}OHoKt zlImJeNEj;GS{}!-I<@21>fu|cOCx-yfqQM#_usF6ot2~NH0Eq>pkFM|x?^feZrpBc zs8cRDQcR>KYL>DaN>JfLC(d&lQW#2;aEJ6Beg;jz11F=JX zhE|O(=$m>QMwe!ylSNG`DWXAgGzVXG(5Dh|ap#1#lCTa2AT(qI)J@rdFS<&}-F-owHe!CFx6PHP$GCR8+g?4c=;*SaC_(KqCV@r~-M{r9MPo|UL7a&-;ZMW+x%|`g9F{_ZmKQ>06_#$J6-qctTm`=c7H&+ zn_$)!3G;K%WwVJw7&Y$%2!_P`OdurJ?S502K>+HZ>`4yI}=iU+)8Tf}(NhwE!~cWKr(dq0WU4s|j(W zFxz2ieYVrQskT4<;zGS>;CRHjTxe zY$*;zt<(svP}0=t6=$sXb!`@P8R*m|ie7dNN~n)6Dlkh;zcE3yscTY5Z5RbdBmxqp z0;0yy0dcZ{nsYHFf`??wLVCXR^9q>~RcTc3h^;0BGN<8z9ij`Rr215V-g2yd5;?~j zwn7-vN~<0>Ng&cJtFM0aWs`5#X%&9B+qQITb+~U!LlNbruqD00 zDoTD@!!yv-8)bFQ!#AbJNbj|NWAadLfLwPq7Rd1l2G%iVS0Yv@^*C~6FoZ{%*pVVT z&o6G&pg7szxjYhh9<6LOgCY^Ee3v}w4kXTOT;D$54|FZ8%%)#H6FP-bhe(jzmo8g= zSOHH+SI0WU(IFv993-J=DIESX0XRB#SRjPnXFu} zu38hYq&U+eDg!c@5tOt9WP+B;3Fj*)AxE8EWl6*T-MUUV2^88q(?gxkk6T z!Ei;S!=$`^0>!uEt#jIB2<$rChmIUsUK9|YSqV`oNd;Qs+Q2o3H*$CW1?jH!GBVN# zXaH?{am9Yhlz6VK(dv`zxeeS`70FmgSH{#X6t(eAB)FAiEgisC;4}31~)BVN=t zT-T0iCME|GcjvOS7iBuFRO*LEkt!`Ao2oJx654}FZK+aaND>4_{w2@7*djXC=8B79 zX$b&wb*ZJYL2M^_9QHlBAJGdOuZKCOBDS-zuA6Vzc0j(m_?E3PMVn(%B}0!#PWIex zqXd^C$XE5jh5AZ1t0Xq^N}5?a2;)EqLw9#YtCyJV+Y#9J{XNtg_vloKk6Cv2#zKWw za*qOPN@N$>RB4%cylqblNGow_JS@3^v?OH68sc0&pX97en42`QLc`9)jr#WQ$v)`o zXHqSC1-m|jWznU(1-UFoetT*SKQ9Clx0EtT+&>8+BR-VtW<5~J<;v!_&`llpzCpgr ztcnaXi05F!`2dllP&!H4&F%Pm+KYALrIReX!HEiay6rBlZ_=vu3VlW@5Yci%N}g%I zDM?y(5H_5Z0y!r-&wCk>6DixC2n#1QHa6>r7g5A1>`8FEs)yEQW44k zR^C;^*rEVZ1eXF`zw`G;POWspwPI8#_V-K}i~xf`e7~D|qSH*P;ofRYcOr!~zj|aP zK&ZO1q$~}HDR_u_Vmk}K=qjHi6#_*Gn zIp?q>4O5X~B6`v*1*S}fuyK3*I;+RkyIZ5Tt-j2NHx17HMpLq2(+v6~w)e|rA%0VC zY`_4ip}k|Wl&t5G&d2A*;6U4wyGi55m5vr~r#(2aNGH_GzMWF&*GB7=6d3gbLap2H zHuKm^Don8SbpnzKf?Jil2e~7Rajw2C0hV_i7YmSGbXpomw?B_RqMp-i$}dsZ(h3yX ziJ{Uc7F9k(pDCX$=j2M4Dnm@NPYF_xq^rz1;BW~#-|)W#J}h1drnizg-?GN>PZJmc zjd8ahyV!p_C3T2)os#n`+t4G??Uc%Hp(0wDQ|>M1^0kSoR!W;BDIr7B-grpJBhjDW z*qA;V{CL1_p<0hl#FfM1c&ynTAspMdFoUFfasWW;{{T_$3*PsKYC?@uxU!VSrP4wh zU!1a%hKgNi1v(Op>{`}#j&d=tC})L9hm<_#)f?M`d{JJbk>g`K9JT^TcGPwtj{f0J zWOPE@>U{y4^N%%V-wSW!6696+(H`23%5moLfxz`CyaAuWu5;;GpVP7B#pbur@;JS} zhpjI%#PR7dr1IbD0MPGWu=nVImu;Ex7M;^{N~bqLc9T?xKyC~GRKng{Z!Oi8td(*Z zDo7s6`3-q{pmZ-RaH0)-{{Us*oQC8yN;o3Iy8agLi`vxby`vVLZ$y(4r0`)?SvLz5 z$gvW(lHyk8L0gK!CxCX09RXI^#t zj(rZDU#bY0H|L5Kd#+Yy>UMfXpFkVbyN2(#QG;p5%rqREKUBQX7p?jLMsQG_pe3Aw(nq z61NG#&#Om)>7~dy&F{J!_@wbb-$1%|Lx*MD3#s1nA5$Wx>I8`UQiPXWExJ}*TE~)* zwGuG1jBo|Q0PWnWGZu}NXzPtu^11q-P^s4{Z!*PE_^>K9B{0)WDNBnTIabskB}z#E zgoN-CIn#M98zQ5~b67W460hLu!0VNTK&VyIP_=HSV=frDV6848#Id=iJot;iPzY>- zQsPyF44m<)v-<;2MMU+G?=W(IO}=WOc%HE8T`%i=hpQ4P5~wwX*v&%KkeB1iWev95 z%19)sw^UG~q&NWu!hJyG+}E;UZ9Ac!*FtQANIi7crQKD^rFN*|knFb$$z)(CjA04w zzzGQ-rmnIDA&nDZ9;e2Q(PrS$?PbKTY`>2 zI>g9}T&~%5*fX{WS*Y0G^Ftn}-Uz%Z5+kycPl+Y;R6nFGZYkCIVHqbpXV!DH5>8LH zi^qsF)Uv!!FU@v_jlL=uXi`L*wggw*5%BU=ynsQ$$nHSF$G^`KQGv&UuNtZEFWjVFiSAl?psSS=Wl%=pSomh5M=`Si<*4hy1w_7eddWh{-j|w!D zh;ZXN>Kp-WB>|-&Bq%zel$4w)K|>=zmXfyh(a=vFxK@L$-W#lEyfRy#6-$c>@uA!4 z^6E6S2IMVCLyoD*Ad%-Z6w|DNMpAzXJ8`H-BbY-^3W;N6ptudyMzH!p{PpR|s&OqE zo6IH07K!kZm*qZ&kV~o!t!WzuK=gx^0z2wbDl)(@!6m)@+w`U!xIh+pgZV zW!v&?*Q!e09;S(6Q*)4U=@`la!iq&j8$Z>BVB z9`&71p{EgPPKq0`R#NNHA7Qkk*0cbZH{nX&FgFFK90F($I>~m(rv?T9!*#MN^rNO# zyK>&4#k~@m4H<<~UXHjhLy{UopLO*4t^RSC!bO5 zQ-V_>W5pXEG-QTWJUxZ3__mMvLC&UhlA+=**{og=D>TL3)S8^;T&B3P+Uii&=yia~ zk9SkO+y&uIB|v9z!JJub!LkdG zT(w$*E_^K-8q|krOp&!xU0&Ux(t@Oc$Uq2Kf!kSe&baw4^HRGbNZYRQQmB%P{K@&NhaApZQFbg@PuU}IMYku$O-GC3fL zZqy-BBt1GDm{6Ts5~)tIOK8uz;GdTr`5fxfZOBs7$z6JQlq0D2n-WmlO`5b%HA+9S zT}U}UEN41LU`g3KK_pW82i4m~49<;T&x)){g4(9K>=t9cy>6_8pn?zMAQON)9&w!q z9Pzx3F9!YAgpf+clI9WeUq0z9uHCqxnA3}nI#k<;j+4C}t)&DUXScV0+C670)8OB& zH<$|Pg_Bf)YEOezms62&S0H(zrrz0>!zu_;Q@JA`@}j=O1e^~N&5s44@^DRmJ(lN( zV81oRk&n7Bgwx_HsF%k{JVMbbw?wKW*W|=Z6IY>A69yc{gM~^i4(n1>p@k9%Nmg^* zXL*r$q%L%PxB2v2(Z@G~&ci0bAGw8r%vk<>JS5RWJHAqmej|hD`wO- z+CzYYm8fq}DggQdvyByroe5xrB7=uF*Yx_Jd`rS)l)3RX<97RW_Sht!*2!(9?hw?LTH!_+6+Emf<#HphxaPmstNDgcw*@_ARXMn{u3 zinvQ4sK(%atFkj=_#9>^j;To8*B;;DTmJwAR^6%7uA8@2f6A|2cVb$ZQmnfA7?hpi zDsCp%IoR5=eJ9pPRya;J^a#d~xYx}2PPcVdqDAJWC43C`m`+CIBB3F+)}fE@FW>X$ z8f|3kLWYnx1vocbX}3p_5xA;X;&aMMkO&>}jz{KlH6cW9m#gBFwbewxs46_z(y8iB zH@5pKSOYvOC03hs8NL#~s--3NZfKRa0G7FiE=ic;; zz=%zl##Yz)ZoZuOxv=dkAEi~h_S~~z#Hhu@*;N=#C(ZJTzVS*K8RZQm>;jQ;>@2lLjj$BFf)((iIsaFye8xK;0yykl)>Vb=3`>&HDrL!P- zh3ZYUZc-gxDhirvx{8h}5aXWp4e85G5z% z6XlGJM`Qkx^g;caKIiICy06v>y}ZUEqL9Sa6ZdNnyv@XR<;5=oOO( zv~AP#U66h}jr9->?kk4{TkpHlm0hxKdOUixy3InMwL+#pS9wdHA%>YRHRf(78=iD+ zKqqQakWNmDhftI|qQ%XWNF34C0Q^FAQ8!OoZpzIi#Xkn4C8;ealj+Q6K|s$qNl8!X zu8P+cC*CXQukufIYCV6U_f4}?TmJwRL#+HuDPgrKVTlMzvyeC*Vi(+v1(%a<#M$k)Xz@uDr6%SvZ<75YRY$#q9is{0VHJk-OtaB zLl-P%g66Tn4y0B55Ys~zIP%#eTyDr|y7;f1Ez%;UBa3)|J8*lSZgh1D-3w|v#v8%xZPbnl7(R@4mPB?UEuxS zlw2w!oCA$B4=Q1#otNCch4@3YI#Wrqq*p|H&h@rv=%hrrXT||cGKW^+@){*UvJ0C+ z`Cb4S@2HoPbWsnKxB+_&xUIjOs-yg%c5PC1@msnq={2;?ro%w0Hx@Lw$}NC|sck%z zgh*^1yTVnJl6!)2pENwlYiAO2B5Z$ji>m57DfjYySoP~J#HrIOjQmWgRT&P{;kv!x zx>{{2WVOgpKx`nd-Ob7UldBsTV*zH?shz?1sPFnAe~Fv!!~XzjHLEY9*4R~f64cdY zxF}eUHbZTcskrS7gsren<)kDNfrTD)yr{-N%0GAlFW9PLe9nu>*lrvax~4(QnZ(sW?Yrqbpxi?#Z$x|PP$uu#5VkTN+VF4n+5&tDgxYoe7S5m zr1A?*BY7d!A| zO17p)a&(xLAA}0?kfg1@EEQ}}E)tG;^$h0~(z-VTR673ap*Tg%cbMU;dIP^T`y_rJ zJWF(wrk)c^{H6g>fCrCZm%AdhL8hjDLuY1hFI9* z@Y=F&&DTcIJvx0?1)ABh-fg7a0ado$Z1?P`Uq!mTbJ`tGP0MIfY0WMZQrlZqKfh%V z+!$IMCkaxLHtis1Df}dHtel1nkU$hVBk;0ai2Xx**z@1neHZIDS*we*YbKF<+RV!p zpxo*ON)$xYBL;T)QP#rOxz`J&4k5%Les7ou3BerMjOoyAcWr!aK4WMQ4PBl_{{Z8% ztX>(qgIekzR64RQh|R^R&7m~XTWz5jw<0vuBq2>Cf##5>vYc|Dq6P;YCLzB=pGIH)McRn4GMj&iv$mAeYxED2c^nqS>p45qx zWd+BTDWobSiKtLpae*o+Z0$-?mX<+K+6W<8(b(+M9+I#!<#C@`+=}H&>78|}Rr=jZ z>ZMjxhi({CS$)WC;j|Zh?r|zB@||tuBr6`YDOn3a1xeLT$9t@TwvUOzC^?ry zp5G#&J}bIeb9Bb|>D1a?P5IYTi+Y0E(-YyNrE!{$(r z#~DuDen=K&%Ivt`hhg`(9Fz21uD*nI!q&6}a$;?-E^A*B^aNB>=lV$_kd&jGoFydp z?lc=bav0v%-sfSrMXK)!@iPRUEr=%Y=aF?~Ivr3o*9eCE{S zAs(EmJCu?Fi3%Y>SR8A6TfDYta016a@}Ci~%{(c{j-59^T5}b#|1`Rw(xEQBlP@3L?m+%W7L;Z;3MFg&}HJWT+w=i%B^+ z7}e!~v=xUdt;f0)_%-N-oz(lbp*rTRu}q-Tr3kM@Zdzl=n1b52mY#7yCvt*83H4z5 za0fi@ZcE{CV_VNvyWu_^9%CIN-Bq=BN&HrHX3w-G!gj>D(RWkO>#^px)V3wAn}n4h zIO|6Ms3Fm`h>t4H2rI~c))YT@XCHVW9L}Iq1%u|3KTR@tCvF+w1IrVY1;(3sq zCr0Oh_YOVzACe!zu-@FT^3r2#w;>vP_C}7mMjakK8dD{8CJYCI3fkm$8%t_%6oZk!0Xz&S93+yXj+ewTYBt9a z``3Q}xjZNYk~(MX1$|FX@S*)eE!@_qx0s&WRmzQVx}5eMBq4;e1uUSIlec!|ItqK| zlfl=Nc)<eJ2UgijGEk*3w-TV7 zs41eYs>(`oeJVVS$y&(Steux75HdJ`7Z_bNd7JLc>RtI*iz3~K`zmfUXpSe%@{Z=x zoypjsmHA#^I2hxx)>Cts=V<|IyTfD+^9c#E;kTNPRjJXU$a%<5O-!dFI#Qx#EU7Jx z=ovg6!6d719PphU+IOjEy5l-jzr^JG;)7w?6ok6;<5iu$PTS5YCSsqRj45&}sJ%21Vs z6rR9^an5oN%Uy8cdFzD|rk!%QWmYfu=dk0Ad`&i;=A^m8oJ=NCqk>P%kEi9Rog-v$ zj(7UnC?4AnqW4WLYHeSsvr}?HTh{#+oi3qMjE9SBake885Ec$WTfSOy4t-jkP(hJq z+?%>vV#(@_&Wc(m#%5G_uF6VhK9-R0mN$8O)lW;SbT>F$?s^5 z;y%V)o~^e~iCRPl?q{1#OUjm|`7+2uh+B){Dpnmz_XFuEJm*n66KcmaZJ^pT_@Db5 zrCk`i;5Q}eieypglu9JpbdBsq3_H1K-dB;o%ynl2)*Vm)1dR>`xdxO&-~F=Zp}mWD z^xoN}P#L(b*|%t5W6iT*XCkIAmU9lYL1y&oi z=@f~|5sU~gIH?X*rx)A~OH<0gWFahu(1e4M6P0Ll;q8g~`9BKV`M<>#9&@B-o1lIA z_e1-Ws52(d^ZvkUn^9su$r2e-l9zUmTbl{SR6ygfIX(1KAnAOiHeq+FsE)nVYS_N- zYf^G*6e-e+3UEp+A;RNM5A3?02~W`Rk&(y;M?Vf3MLoCC0gvLDSgyF8x8d_z*Dm|U ztRyeVs8gX#1&5euIEc$$PErBkAZ{QecIW1D(c(hF2^L3G(|DFdpo^e+1BDT1;-{oE z0)s8(N^mwvLQ*+AdjX>y;L&AfF^+lJ7;7CrwAtzGX9e>ucPbz%d^$6f`7AdkIZBT9 z_c9TKwOo~wt*4&DSuM$(&#ePZ(%zE~9kAb+b=A@id~~`UP7BD~#MmoCt*JwlC=j%q ze1{$NtxbDq?h5BiOHX6;Q$%&v_o+agO@62G(C47DC5a7!g{4G(BgQ$$IvKcl>~M1< z0FJbuT%381uGUCPWc1>_Q=)%8>kP-ITdq2|&}M8)QRcqbB~8ahK~fSDq?M!;g(M`M z#~QfG&0bya*%S78Gz5CSO6r`y; zfJ%aruy`Px9(nHa2P3q%uYnfRZ^%lYmr}1#ps;B#m^l_-q+2*ITYv8^tHX zZiJ1#ayrnKJuclTBJOk5HUc2qiQTAYk2PEwp9 zApF2i0r~!fZ=Bp!?Tia+)x*4jEycs`Ror zB`5$B+yIa@E45kMlqg?R<;M7z+ev0ygr6}=&vWgnwG~)#Of6m2tERCPhSaH5DGw$y z4GzvJY6(hDIOLEt#L%@M3y1-IJ?W=Wtxp8q9IO464i!qM^z_msNNJt_0Bcn|u(w`X zkEq9vlYrPz9W)GFPyX|DFmr1P){KtDFE@4YZxP+$^LAU-V7da*xu+<)V~XLJCgb7OLqN6 zDk=5bfpkWytrfb4mF2Mfc|ijNg~vW(K*1#n2Lx+E2&g%QRh~ni9I^Y_fOyQZqgx$B zt51hTYL!rCQdz9Vgu>AjxTacKCLt;V%1gy+I}SZvfFyx?L66c_M9mKV<9=!D!Jk-H z(22Jlc74Adw-UWiL?~2qImVuqAr7TTQd>YJY2`zl0!}mEMn@wU(p=s89j#|ei}sKh z{yT5_DL;&V5w~YqdRIiIIZdL_XaZ9;Mrm>BYGznkQ0g}=^*XJ@610$%fJP2Zl(_;y zu>4fx!frUG>^>B!v@F!p8j!V+R0+Z7zsp1Nl6$!o7NXRd6!#nq#cUu+RZHZ3RI} z$0<4occLUj>jF-a^^;jn?ZGEVfghWI%Fd0Ed1 zAD=9EPpixTSH)EC1+-d+OFTa@)G7tpYySW{ulku~`kh{fGNmCB%Kb49lu7Cm5Uo<|dzIFOitxp!V{{UBG+*VYgE~p|$^D=VW55C!L zZ^=>=Fo59P2}+bQ2t4GIvD^sLcS}D$EiY`X0if+yy0{)PJTF_-$o1Qv->gV-zY1O_ z(*%95*xR`X8O zV7A#@XH~iPic6b9e3cI?B#gO&k_xq(G=gUU-Ik^tV-y{GgVWlSSHvfaK}zY96?!*V zs&@*i6ww|fDl9P!zWae>rPe|=w15fLplk zPaK}gncA_Rzo9{L^m0VHH3|80ABqV>j=v@3EkSEeHl;-+Tmi_&dE;*!w35NX;_`Jm zq<1}jY3k{^#G9rCDl0Il^cbwThz!JKVV6>|me3M^X+!{X$sYV`M3KVJ1hj$`n(Ez$ zRqL(&W?e98NmLuUnNOO%T>Ij4PQi7;Xk~7`3anlv z{?h56h#I|Rhnq}F>upz{zfXU1B(VEwCDbiA!CQ%N9DWnKzjLJ4mVs-Ukm-3XE1Vvr zQ=;_VO#m0#bi=5~5W`J~=$RqvY21Y*ZW~h<)D?t+Jv^yHM1m@nB=%6~H(7;i)mJ5G zOe&Q2AxcVAM1@CadG0oxc1n+yN$ynI2W;uA9u<2d{{V?*E1fB%(yj|Oeb0ia}V;?3%R#OGia1B7ALYo;G&l;r><8@V(W` z_T;Ga{m54e9HYgfIZl0W7!-T-bqXNO65t>kU1*^#I&t)F{n41=@N7!p}QLn7yHU zQlOonfZKnL#AuDCI#AjdQ=QXKc=x&B+o4g_p_^*#Oyl=YV5a(yzK zW))AVv>$p(swg4d?jJFE!Qhgzr2~+xgTcwuI=x^<03?1(V=p0(gB-SU;?}rz0ggbi!2Hh zcc*cEHYn*Tzdn^jq*AIa%wim;+L@T}6!D(pP+W}LOeh~xmZ#KIfP=LS1!QtHYhDW| z6@!(JEHAklcSG)sLtjU2G+bAmp$e*M^}n;IELNRcCLH)hl{&Xmz)EoYNy7Nb52WoG z$;yq+rvkM+D<(W*=E&P7tGCTbx~tZErstPew5hZnpRT8JIQ3QeHoYxOedDQlw*uUG zC{W?mloe+RP&wy7!-_n{$Vu60=I1yxz`)xhk$;)3{z^I1iE${hIu{mfYLsb^-mT4j z$Ei*!q^PMuu#Kdt?WK^V6oIf2ocGs22sLYty&w=Ms{a6Mw-r?}B6~tiW|O&1t2ioG z10y3K6P$K9(>Hy}sG(wr$*nwWluN_|KOP*)%*1Dp?@Go($F;B_iT z;ybIa^$z-xbU^Z{l*@uDDj^IY`HVX7KNQG0_K=r=J@%2#s`8t9(QnI;jUfEjTbi>G zJ{-DA;uP~$C^POD(cDX0F(1u}>wdq)Fzc>h1L?|-xz(%$9Y|-rrHyDCj#J-GZcpcB zHm_8Aqc!^Ys7R4Aa>J^1)hs1JmfUQV>d1JEc5uF?nNh zTO*{RK(0HQA4Kja5VOkI9nSlZD{A*B<8#Wd(Qf<7_m5AgOs78zu$JXH3P-{P$z?#4 z%PfN<3sD=Egk+?JY(U+venE)rc%o~;cGfsIdzH{OEWfl%BjX{a>$e+x6?>_58mUyg zB-~TnjH<(Q@foQx<2Ke*kQ+mUBmh;lBh`%Yp8ABjzh#ln*f=(a#Glzz++R6?wn#1n z`~c(OY9&ay(FUUX(wH+EQdX6+FZo|3y z9n^F`A*N?Zk1np#oL14gn%s5mM?Z-|a`^WNKP@hV6?--5A-|QZbn=Z^uXudDY4PL6 zesy-{p;3pNvK(l6a^wZ10flE^1m_?e07|r?$0gLjne&4kxbTM^O}49jF1a1Gs_it) zs(RE4m{#OEm0*SQ{h$(|o^VEWIUzBhQlLLj**Wxz>!4HX9(8r8vfqrNs0^jS@T9nf zA@n+ubG1n+`~VV1sN))VgLQh7IFL5w5&AP(r_?&yA+p=d!mPrmP-BRx0mfAP2b*VL z;0!oWF~Gq(zHKBC(Mul0f`}gE(t>nW^sh|oJ%>n{G1j6;xasW6W;ja=aX%E^ zJAB5oe3lcqM~vK!h5rDQWa-2qdU%AC-sBwF&k*D}DfRrv*JI<tt)B>y%$3H0 z9^oTrs48W6P|R53g~3W zjv=hVHXACQx|&_->+v?FD-~qOBo1(B@(wvh)-RpI-5fej?3K>bUu5O|$tTmc61xRU-*`H8D zjmL!n6QYc$x z)ewO4v4ZM=DZx1OjB&}|iuDq^c-xBVa}zE2wMi@?xs_PzZRt!Y@Y02u^a6_Oftf}oJ& zWGDoLDIq!hDM%UM>oRD>hSx!lB)ILS*!d>k34J`hdYyFLw+$Y!s%26P6+GoqYimpg z-*GDfGsTjXrwH8m^1%bj0Z1rT4S4k4iZZ#x>L-3so|kRjmUmgIl6r#y-{#F#*%qzI zRftmi5aYar#ao4V^ae;})Tu!rmWBxjop%5l09^SF58WoV`fXmML%eOPhK%amgG#w6 z3Us&wKOYI!pKzx={IUYD2Rp_!3f}8ttYH($l(Yr(3aU9Tyig%ZK4=^J?OoNTWt&CD)j3 z8>LElWP*est+v}EB}(2qCpxnCq#zW{Nd;@DwKuInXf-)*(q$Al^ffdVgg%ve7KD&W zSAs!Oa8wn8k;bALF3N3NQd`q#H*Zhw2A^sY;!0F?%~W>^Q7NVyZEIYB+PMh`3gJW6 z4gfvCnUS_w>#EVfo$yI*h@)fI&3ywRo zE`{y4C#uVDkHp^`T?7`De{{YLU`BD!N*KHD~)JANcpHXEsNwpa*Nt*1X zOm)S!JhD=tgaoz*)Q}P~Qhl&aG_7xzTvt~E+-0Dd>4xO${flX^-p^@8Jkif=dHb#yA07bWxl_c2CjpyOFRL9e0Q0{s|X6a0K z?aC})Hgggkd6I^=Bof=L1t>nP*lZ{%B#bBl&bpjvT6IX~+gdE|?^|=fx3crU6UviR zSlIGumQ$s+H36|CxD)q4=8g6VFHf)Tnb{R3IWf4ESw51MS^<sejf24n=zp4B=^LR|5 znFD?_QU3sIqts{~H4VCp;T$>-ZA@dKR`q78T81Ji=0lAI>(C1F_4ZkW-pSBe4dL;)wMMg?$KZwA7a3Pp9DOlb?#PJ%SYOP@sA2pbu}J zs?yWRuZHScjZpkbX@c|>OmZZLT!AA23yCU1kkWtMT2`L_06<2hL)t8EKb;kRja%%0 zol>gzN^U0eDwh)Giqq&ga04PDfgiHw6SwDrtP!VVtUq{#2gKpHw8tLKyy$EXx24oz zw6p1R?~-wj0*Vx*4{Qy@>fl)8OhXX%k6J+nG&f>xjO})$?l&SOH6j}vdnl4I$T-M9 zmX09xRW!D`pN7Z@;_3vedVP^Cm~B$$Jj9n8XjDEe#>yOMrAs?NNyx@I(hUym+Ftsuv3A4O3$_>3Sr#Sdhc6ZaH4yR8lr$umdNZdOkKQoZm1yz6;4@ovn74 zHtXJ#&sMx9^*+s_)#@;>_d11YKu#QTi(TIHYvb-qD$km*2+x*C{{SO2wh(9Ea*abXRCcsomOE6^tqQI zrKO}PH8~%4Q-D7TxWEHew=XtF0j&NiqmPQl8ff|>hfHjG^EZTR#^#)gx}!d`Sd{dD z`3yb)Ly8&C4ixXsF}#!5oeAPtnG!5TrGT1g6RI!Gv?Sn8chrDss6E}@s8(wmy&NN{fRRVhs=YG2R#qz|YXO^K`} z!>W^~bAWGTK%sbor_SiTR@RpxvpQNSasCyyQijr&<-Ggj1Ms0JC`bd2M{}WD0sBK= z@kjlsryI*BvbX;L$=7m3>P;Foj%55)iyGpManaW$K$amX4=}a@h{}o!>qzaxgB`K0 z3L|mB1LJj7TN3xYZAwC@Rcnr+9@m?)avkynR4L{ptsYrR z#b|O%TMiS3(VUT`Flo|R!k#v1#>bK(ER)Y*fnE?Obec=GtIGGK-7nIZb~HLN?Ydji zPnJ;L#R65%{sNC|49VmVY;cjVB>sz6!m*j9(&V&|XbyQho;m=Xd_Z_q zxno^-RGWUzyqKfX8)|E_?nVM*t)hgiAufd+tOpWygWqyU1ZoiG7SNlLtMF9XY4n zj;XZS^@`Dj3FlU?jd8QT%aF7L>Z|V#jq8M1%0(lvbtP7Uk{YV%w|Q_r>pBsJ7ziOQhB}E;}fX z6J(hQZ+XCZY2{!g8Cr-?Pdc~5+V;vDriWA2SD&O~x$kwl$f3aP&~*J(lIiVcKU8k$ z)tB6E8#Jcny-2D*Aqf-9VJsO5jt)GgONu+nj^f}MAtdXlF0cbv9j8e6s(IrFs4zOA zNv(v|+(oHNl*34LoXDy;^XmYhk`mJ!k}!-Ccv^}{N>W^y-dqMpa;OsryGuf^{uKK0 zarB9qKM25Fcq)`t5^L_Elr;K4QrlZ=1*cL_aN>QIub#Pln8vW-$z4~5^`UA#S2rZB}xRkwX4+Xm4Hf*>4Bo+j7BIO)=q9~@};+Z(b0Wd z>1T@zX7;eH`_6pniEfVjk|)#ND0XbB#@{V0u#}{Eg>9%Q7#Knc+(1buLF57u@vyn1 zj=Xy+&DDOWJJr7wQtis*Z?fssWL21EpBh<1Ek4v45)`)`JOCdE-mU-%UI@;h){XC~ zi{$m`9TZNVYu-I)xNZnlu^yjrvnmadE{f~LYL_fWTTZE=_)?UFDP)6yqJj>&?57NQ z8qx7vc-pd9;&vP=&2-w;*J9G?vS!D2B|N(pDGxRgfZ+v1g`5+PHv!vPZ6TvoaOGpajpF&ch-x&b+)i}S>KfUfWR3if!KmIu0cGkJ_@s56TDhA(q5NWY>UJ< z1@>B(BGPxs!#9DlRQ70*A-<>HOUcUVs~-z-Egc zT~d3aYMX795|rlzgmR^oIi5h;FcOlY3Da0;wL@B5Kmy9MUKxB9(oA}td#{%5!A7P_ zMkw%Nmz$KOBbQYnhR~(9f|U#vsS3(Y5}MrN z>J7O`jX8={HsYY%O+^xX)vUh?L|2|in61j(L_7qN0PZ{EQIFRirIkB;rx^6^IotX9 zCk}u~u)1ds*Su~-4Xs%cWGXFMBE0vBtVmOjh7`ik`bryZ2y=E4p^}ATjI8HM>SRFt zYxP^67|d3Gc4rPcoBS)cACE*Ay`oV(OI*pR(x%ycFLpRoI(@wBF2iZq=_^}#bs@xg zyzK0hdSnFIZ&uUqr0h>>7*+H424RQ*vXt z)8(?$Wv!}8wv42VBmk0ooZ|yq&GhoQ*6b-mF50ys;Hrje4@9NHp33QoTTPN7?j^=l zkUf&<9QWE(I}Hz$WxAR-2%KF$VQb9;we~;qg_pljZs(kVL#ONpp6+-t4v`qs&>C&f z%!IU-g8e^$5}bm24Dq;oWDz&$E+kpH>bBdRGvJM+uuykE4*f6kQd(uKxHg3n-F9Sm zo|Pgwp9#o_^5OZ!Dai^X6)C{kz);2#o;M9$Hj$@p2YTnfdR4=c*zsQ*CAT<_Np9WA z1n=$0S7)icQGsDo9F*HCgEIg(ATq7^Q8;5DWjRW)3VA1vbB$I2YR7ZQ+^XSy(56%^ zbfUQ$VxumzCaqARNZK8Q)XToH>>VwN< zMG~bpmuXkyKRw3YQWYXIG05JCt6F_!!r~B;K~e_dcX6R|B``Bm)4;)IRJsoe(#`NU z(2k$mFGs1>Dv_j032p^SyIt159GQW3pt^1%ZrN)%3VN^{0IJvV@OjCdJC&pwB2etaK_=lom4 z=FWheVg1JLJ_C{TwR7y6M^7(1vW0ymGOtsrbt(dKqM5>uRz z0Vn$Z0K_N5$7Vher%TBn?Qa$CYwvqZ*V%d5wBH=Zz67`7F)P851dbGsdeHR1mNWD!MeCsD2YFJ|)HBZ+tcn~LgJ z$PW=#%?gEGi&nK;QvjtvTE7%J`zn-}z=DX*rNtp_Bm!`pjlm}bZX*~2U6v+n*-*4j zZOz#Ji_dehVuE5~9+Ui}5m8c>a&mpni$E(2(%ZrB)5DDvC*k19Y$T+s z%={%IgzUz0pmu{OU0;>T1S(CKIMjw?@lqTMH#;P8qN(GQH8-j5t1$5F3~qTTB4PMjc{ zdTW&TV$|u;TTBxeDZ=ZC*xB?gD%+i>lacO5xhMHqI;Itx7JW=U7$}=ivn`A=IC$I{;(&@^-?qt$wFcOFA)ezh$o?t*q+;E1_rGI24 zL=)|e6(ht=FLBr|ekjgFfs7lwg>; zB_RkY81oW>agIpWF#iA=g|5^ZNL`~m10l`Rta0){rmOPe_;ZcZ%W!!WIagAkR{W)c zhhHuaB<>y1b~XY30MVbA*I^sA!V7w?CQw-S1ISk5uT8h)_xbU2JbaJr;r z3`qX~oGl~Lt>ioJoVlL-=&2(Hfl-a_4R9PDRY~yq)243@wObITE?A<%sIvUk2HaZP zjFo!M!~(1wfCp|)?leD^8@LKhbEP4N`AE~^&iGAEeVI`EIt-{&?m3J-1#y5&jh}}I zGFD25n6zhrKte)s@2Na+3amKp3b#E8=>?@4?{e|B=@E^y72>)qEr{G?0-}aWigKi~ z2`Jo73Y$^nbDtvv9#*>_t}rT)Bl$tPiBZ1#wbKi7gG`xKtjLbyp|*qo?4>SBe6%Na z03k>vMPG;2o(82GY!?(X<94(S`A1vI-A7$IUuV?r3TkOGqcVd0au%joc}iCHn{<$p z_DBg*(x9{gFaoz~w$OMKh?ifI=L5g^PQDjFRGj&c({Ns<$ZZLNSy>AU z^3aj%{99Gu8-d_~sZQE`0ENVVnGiA(gWXv&JUaN(q1CCelKrE2mg3amEP1V=a#HMa z+pV1LX~KY^kVfRF9zfLgb1SG*J4i2wC}&u#Dm{bZX`0+WjFNhZ2CY4Y-%v4GZbdn4 z$!RD`O1#!xN*qbgDN+H(-P(fyEmgc}l8*OEgxBgOW>5qj3UVROy zU$+Iy~u+;7&fMwT2i3cDfKJ`alI!P2m9Ii>qL%$b0WD#ewSLcy6;sj z$@p@k8mUv2N|>*SZ{m?IQ!8Y7&6Nct=!C4uBzCk)r46UXP$biQhOp$ z_=UG0W_c(IOPq{_5UzXXO=CsrP?|@{>L`Cwg+RTXVpLbY%&NU1wq|*!Ew~o2l|D~o zs1j6tkI?9to2|izs>{oh$$`@WWuThxT|Q{-di5#wTsFT?EQ1C#5D`RyDdmF9Ri(|P z^>+su^9qhmNj>$`_=s*)u;M^zpwK-&E6D!^4bR#Z~7qp;omV9p0R zLAb2Qlollw79rPYPI*sZKqw(@ty{29Io*u%duWEbIeknw@F4*sWXJTmw0-RydQIYe zo}<%^CYvU8uUdlFnIatqI}45F?f|c18w95$4{Q^uHU_xwx);xI6~dR)Et;ii3#dNb zcB*{C_jLaNi&FOcE6F>80VB6=PqwWM&?p4u+W9Bsr0^(rY$z*eKD9@4Y1r$nMRVpi zAw+_B@3Y%c(-}LqigV|Iv9N?Px~kcT8>X`2R1{Jgj*l$_1K2GgM;}JeJNMS8$8r0} z2W5}+pf`&L>ov+%sa=yrrqkk6-g+X@36(ar7lKqg!c?N8_h%Ww@5efphPTqwYNx%< z7T~^ye<$6(&;J0sMVnEdFgG1+KB4grgdr{bLc&1=*+Frz%6n>(HA#tiXmi zg`GFBB?kJHZMD-65|<@H&GV`jq}Yj{G8B_eTE!b5CSW z=@*JBeJZaC12+4nih<>>FntP2)ByuH0Br~4PIOVrjq#QiZAz%(dt_-2-oh@PpUtTB zgxK{vYUi~e)}pFaGO;SCB+@FtyXLg8!kto}ypro`O3)ILN2xd@>xcoo0K1uaA$<6R ziIHkG6*!R{^-5b0!zxx#q^oL@NjdyLj!uq*R_mXel^wpDZFK|yl%>R@3J3>i`g5pE z0X!=qusxJmwnBzG5uk{qP&SLbI`H{kzItm~zoS&?)Y?54&kOjcN?duyn+_Jx2XdgS z4{rLVOr}Qh4^oVe5$}l14#7uVT2%wgS=bbmqyg=KIMHW>2Pu-8kAYT&*| zUS^2Xo5A-?HkU^!H^pw~v2JSg`UHx6+MRl2rz!scd$lGy7%ni-P(fR7Jm%ErxJq-z zq#3Hh2De3?omB7cgjf?Hz__Y5=T6zL$G7C%ZpK7u04pw^HIz7~3qcAWdNwE|><0sm zb2}0-DUr9RuFu0VPm*64wf**<0HtHogf#xOM#38Yip|p=qNh0E52*{fKOHai-Og++L zHK4{ouaAH5nR-pp>aA|^rgY|8V#vGcby!u}Mb09Mlyd-OnFUfCB@00Xt%*@eRN}U% zf}nI{_~K`m6SrlRg_L4pYewMR{+~7U+R5o>N_;#>0t{$z?h3PRA#OUd{Mo@o7XlDe zNN*`lLO?*k2Z5@9WCDq=if2ie;x5wBU~~x;%hi68-jeFJo!3lcDxTsg?zdNhlG93b zr6@{WM(->udw!r&2H}!5FSJJ2GzW_*zv=lwj(b{29IuN#Ub@-7dW&1O=o66+*@IM) zwqB^dNAz}FSZ{ls&JvOa0VgBhS{XSGk*yuMSrNwFMwC6yn$E3T@avA%%M_Obs6w4- zYjfe+b7@}GkHQLpJBT2t4t0w@OJO40cfvQzaUPPAb<)so&ba7Q=9Kc*E&6lMmy(p> z#jpytAq4EEcRxz(dX0dkha}CXQtGW*aAC9_a$Q18tvsmFV`fT{ zg{f&k-Q}SPZ*dA)fN~_ZKoN=D?;&c?yX$`=H7Kb=)^ z@u}dOr*|((YMoW+RZRvB0SaAGfW)=G8_P%as%SV$*m<$*Q!2nxa#8_K6$1TAsqv-9 zagJu`a8>8R73$^FDXUJV^jM!|GOd$brz%mX(p_~TRT1>06u8^YEu}JDN%EfM3PDiP zbI55uRk)wrIu66H!Ag4VWM4iA`q4|M&WQ;zTz&eT5q}b?ESAPn8Thp{haGvOsR<=x za61U}oav@#pALtfd8G(v7}*|lBVbKm>+YK*_>#FRwb}(9tM+7?^=hD$nUUFxDGVWR zApu2BwD3_maGiw!Y#33_vl-#cXWct3SNQDGIO|~BkLL-0g#%0RH{u$xZeH_UO*-kP zhT2RtwH;HHPuRH3`I`#Z9#a`5l7%Rsf^bOI+)WK`kg**vn=79uRDbcO;kw)DCrI45 z?CWwZy-TOl=F%mtfWJOMB{DX7s##Lp+Vcq^N>To}i~u!b+qHx_aV{dL1@r32lEtTP zNvz6?9dc(WNsA^z3Y61BAw?PBDMX%o`hB%SKmydY9_hY|an!C_=n>YhF(@G!z(Zj1 zxa5EUNk6WY?@BgRg|VG#YHQ znvAC8Ei5Hqv{Vzw`@^?b=fpM1rLmos`S60syvIu0JvZmJ%29vyLWu8$o}E#W#Q2w6 z^{F=fWn?_ChGR(zNN|!6rvzoS{aUlia7VTH`45&yu<$64fkI^Cc@eSal4y@{vHt)H z$n=xLZKqr5?L@owfPHb_lS;Hwqw!9$xd$q6kROsGr5h2P1F)|-IM#4*0IcT%4G~Gb zHf51t>D#o+0=-qB%C}glRoTBp@`?UwE&(Z0+_siQj~rC=W;< z1x9+saLI*z(K?3+M4KilOERM^AO`{xc9pk|K?O-F+;TwSJPk(oL!MRXtxdDKlhJEF z{{XWqAI-YG0!kB6uGF6RY3;5{X+oGr@LL5-NFGu~Na_}O6Q@eN>+e+2B~z-+zc!$$2||DgFQBsLoK~&F%uduHDhN`x z<(|?-lS@^hrPS7!RsR4xEY-X?Tiz|u-NSEPbh>qRkQ|R#wjw|hUu9vJlmKNL)lz<1P%cGS2qZgRyR$sST)sziM)% zjlGH0tpi(092Cuw%wvO15-A-#KTfFIR&AYd))fw~MTvH$s(mNpfsnm{DS6L@DIvrK zI@tw80;G}Oodx0&Nj8BYBmhA6TmA_X8Rj{l00?mwK{i17^T$A~9pQN2)S4YWzy8g7 zaK$-w7pe-c#iTH}=t2scKX6n*cNqi}`MdA|#s;xm&|A$eyoWKR)wg@&`Ti9J>Q!Dn zQWY{>cG-tcpC){u%0f!naLG^zPyiJA0x%D&9OvYA6Lgn@(w7CA{chFJ-{z;i1?Z`=j*R zPsIh5N_|XME!ne_(o;}r4z{7?xHc&&%2WaQ`;OWkXhcL;2&`#*#{lk8r^XeBY{KYs z@@Tf@4v$c7s|}3PqC{LxK&%E)>MkS)k##{s;I_o zsIdylLK6GLr*f1?+5k$9c*aJu^5xJP-v0oiFT>&U9On*4A2s!JqcN|3m-M5jmVL2I za^#OwLow!7nW-@jJa=5daZe#xb;Fe$5uLzstRZg>Ej4SnY%GW~%x#vAdnzU3mf5+w z*Vc4k|PQ%#5RzZ5#+Y13i8G_DGl#Z@tvq7liynSa*SwSAvdRg@VS2$ zYo*C(jf4_7t3MhG=#`~KiPH9IG>dw2s+Ub&Tc=l_hSO4NQWG2(Uv+)R+JdCEk?2Z2 zT!K#{pDs^|%M`G@)z}B_j{g7}J=H=n$o~K<=0Aw4Q}phwT(yL>q{oX3Q_Os_dK5Z*uin~L~c8Re>7%XZjJhnV1bmm{{RHU^veaO6tJ-2{6~&>_s+K@ z0mNxo%r&ajmhewirXHzMt=hdV9NI;8lKdHM)L2`s@$1i^h3>#3DIoGaxIDLvO#En! z>?Xko_L1e0T|ZRm;-kRhHvKIZr%PZ}BvPJ`8If$hlJoIOoDGG?SL1P@;?RW!r*aC> z%7G<29vk9DT8459>g;v+`>d&96{(*z73!T{2TAP3bef0cxmNg(I`FJUc&#&JqXno) z;9;oec1Js%%Cmp~=mz_hOo6Nctvivwx3|ePcx|Uqsy##VZV5<-O{c{(R_J{#K2(QW z2}?O6bBZe35;-8BmWRq~%tXh^GsAqbkl!bb-vvt*p(ir(NN5ZZ~Sa|Zl)vK zwwBP*?uDlWFD;~c$p?YEo~a%PEom#S{?ummI=XZG{E*$cWxMb)>9*BWRo5P>)pA^& z>WJe{7l;vqjsh0yP!gh22;8CuNY_(?t??5eqq5_3#4VPhH{ar>)SIEo+}gb+q8o07 zE+>^XYsb%2WTEDl<^#7OO4y_)02LRoF}oVmKCV_^bD9WmP?>ET+9jVNeQ>s0oc%si zFccOCksv?M5#_r!bwP;Eu=ISg z62B*pR#KdVxwn)jDo*U{H00@b_YUQ1w;9F0hLQ(VVZXnccRz`XBKTD1jXI@hxlo4j z0cXpQL0f|v2`WO@f!r6Dp4!l9*n}`>bA!7CN4a{#Nos*2EDFOp3vCNqZx4q`)~$$2 z$>BqCk}x?XJYa92lmU_f)6ZqdOaj3X)Y}$)zm%YtFF+_=Xz^m3u2skI^Jy`uQzF7KeCJc-7re%s z+){-h-N__^NLa=@Y60X5R?6Kj4k~ZdzX=v^h#LadO?E}`5>>wZ--D=9on*;cpGpgh za}D5vPzKb2wLwYt)ZK9%kmf-)<$V6}L*VL9hiew4K96^|T(qBgsSna>@cs^A*sm?M zWhA9#C1h>;vxC^Lm2$hhMqk&xDHNKu#VSoPwwYltl9t(NEi{}q z-qzBPP@iO;I2i|ONKM9#uG9wV>3l~nSp28I(mD;lp6U-@qShe@^QttdRM_*A=0{uc zmeX%10Ohiv0*4^+p5sJ<3eKuiYBgQhy=b%Nq4jyebY-dHwIG#wG4gi-k6+>n_utL$!4!*MgHPU>kua2@a3|z{jxFQWmg>0Hqjo)(PC# z=DvaSf5QhyDBU`hMXB5r(^Qbyj+()f9X|~u9EG7pL?E1jwDL#3xS`_NGRl24Iu4&T z=tsdLh9LG0N2%-b3Z3<@rO~`I^`4C_s*H-QGDMKu>ReFTF_iC9FCdh-Hk7C+V4la{ zU6+FRpnRdu6-RaEztvs=cy5j}yM=?s{{H|T%3tA6s}U_;oLzL%C40} zx@Znr7bPIMDTm=ZB?}5+vV)IMZA-|;a4-D7RjpcAi&s^jSAiM&ik)lWT}UBrd0{VY3K$_tARm!9&|WW%1Ds_Co`a|J z^;&<@J|mkHUu7*e!LyGPYyt5D@J2rlHzm1XTlI^ZsVIQ@U5F|4dNO0B477yuGVX5^^Z|a|{Zjx6zBi9O)3r@g(=8ayM z%m$n?-E2{iwIwJ^uVAG_`H3q$Z7EVn1P}r7{CK4eib-ou{{R$c^v+bc`lf6p#oH5q zclWeqyKPJFtTQVXMcvXGTNJ1z$nDqRRD-Xl3Mun8I)^1;o-V`hR~ z$0E61i_7y%qsWWU;juNh!(2;;0E^J$_l>*vO zq#?ioP~|G*ZP#-biA6m&K1i~>>Te307`VuG1c0oK#XgZxh}}*VW*mo7>b$wKsj6la zl#faBo>NK)leGY{Ecl-?m~^!W2P}xZ$R_C)99G_e|bE#+m?2&g=80i(<^(N}4 zSdviV&}wo+DV0!CTT>1>!bkv-vm_D}Pt0Sn%gDtKb&gj-;r=H0S|f4v{CHMPj=95& z)ygz#%xFp!>PwW>NQoIp;cH6#wH@13fD^)i7~Xk4-8X==Vc2l{%Ln?GEO>+3SZ_#2 zwx`lAI0|ahud@bX-Sb;S+M=P!&NxC+97s_f#AiC|pCCKAagB_D=~W-ZcUJn5MTJzQ zRjU^?3cPm;UW+|RlSz>q@Fm#(YkQe+0+2!u(}JL&at;<=Owj^kG=C59wK1WNM~1vu z?y7|)w`((0sVgo8k-bXi{{SagQCr<^>b2$57^aR9Wy_A0WKj^~aE!?et))JcIpqX5 zo*N3}g{#zeVB;Ca291_M6l5WxVSB@mMf4t()YSC`(6^n9Zd~;{J`8>Bq54D0OAyr* zvZT2oKp=%S?%~ejKqI);GedeVsm>0!FPpc$xlo{WUh<0~PWce(E+N1PQE^1>1fO*r z^Yb~?%rr?@vI{y#Rcib?bQh#l2=nd^tW>FWONU}qs$ENYhfYd>+J$ZYwbf)~0783r z)*eP<-u*G`7gLGhjAVBxw|-wGBI|dA?u}Ere@UNJYDJAIvm!&Z+S~|^r4Eh6r3+z4 zYLmALNE=nb0O)a(EMncdGJg+)a5k^NsJBfm7VZB42KRM6awEz3CvGPllNTy!^22^w zR)TPL@sW}4IL?Nd;!M_&?3yV2ycaa|wMuDs8z`8Dq@x3X54L|TbegY~$bgpINNv@5 z&|@GimX@cMhXR!1Ph|uokO24p06jT9lhVFF$(d!*;&j)j7ma#D5oy$E>=%pVsBJ`J zoHjX9iC)k#-0`V0tOLnLvr{52qerhrAGb9}*rSk-BBUfusPY+gn3SHaOJ4X3}*!bHLvgJL8 zP^R5tdrXH2Dqm%!A$v&R<2gFB9kILngMP}n-!pYWMOPt4EFPpzwt9V4r&btKaOSql zDy1z0V%T&LG88%NMn}54j{4J&?hsZo9@y7yI^KQC6qN3c!>%qe9Z*_O6m!AGHxYnU zj&MF&gK4Id5>%q+>Vuw1a|`VDbn!AotF?w{6Pu_R&^~%j%7-1ESJtH2M>jI&2!spfqX|_fBcL zj39-DDWo!&8!yBp1s_UQ22^>_6U52bE<4ge7vI0h85w9Fd)Y<$+18pRXQ_8Y8f`5# z3J<_PNQ|XmE$5LKFx%VkrL8G(D_Rk|Xv%Snaz#k@UqC{flE&9K9rmuRV}w;Lum}Sr9CMwp>4JbIYvhOtBhd#<5gxr=QXwbw10$TK@+4CI03O2 z)Qc2?R^@klH3USQ^KxpG_hHX%*1&Bot<)@(uXb=$gmJY>CysImJ-h}5fL!A3N2)eh zejj>=(@F%cpeEP2!hV}OR#k++9m$ft;C&Bx#Lch`vgaj-2zN_U=*ZbXnobJC$J&B5_776ZCW$Vcip|a zUtfn8T~%c0M^mf)BkChJ^&U}0PL{-#ha7N{;+$b^kZ^O8zd80GXmawyYV1h7*PG&( z(~A?sZLeooG+0+f>rXeuL5No!<0`o_PnsH1(&`vi)%j>`Zzv&NXZ3^v2`RwEFEZWo zy#hB$7R_NT8+6~j3mXMo?*>)jj_SPNeXSNf3#wE(UR@QJ(=CPy+&){)DYCD-KrS|v zDEXMePCz6Xi6dk+*>k=q&n%Md?&|*l;R?D@ef0aoZA#;-N{XA3@@c4!Tcti@abkJR zEXh-fX=!l0jD~>9N;0J-X;*TlYo0?#3m*mioZ1#F()H)?Pw_rvI z@>LWq6)JAksJ8TX*5bD3zu^bSW)V+ua$qWGx6GLwdFj*Q}d@4HCB7(Hy8;ahz^zNEjh)G_G=$gm4r-qnv0caHC{`Ssv%Vximh5 zWb)=_%rtsqkE>b*pNTuFV|-Tr(~wfvmV^=zrduZo3H$&j0~jAo9`3;o0%(U3`f6F7 zA-5W3-1!Src}uDX2L$oPe?3$PQy`7ifbivbwDbK>riW05sy#id$8*hfEpGDA+y4Ny z%CH(y+A>Z!8YPaPc2Z>%yQ}4Y&yNZ#)7!pv3#HvwVj?82JyMfTgEjEjQd=gX!=Nc$ z(i9Nj!0tfy&Y~SnAw{}CHaF?)ht}Or9J__bsgvX)$SMLzYW`hm2$>uwu;DX$V7BT zYCMhT-i0=_EyK8QHs?gc;t`Sk-%0uY%MUBUCS$*{2_Ez-@hY-)1Hpw`qPAq)iu}Il z^oR;s2%#ZMsZ^voa;BN`(u6XSR5G$uLrF-9K|j_wppolWC(@Md9B8IM$jNvco=VS? zB1sw;PQ!uI`R=ScoqfEzBLZ!`L9W3?I;R<`?K#SnR^F8nxs0LUwq0MV3P}KD5C|Y+ zu^L=@^t>*TJksWWZcUFO_&^S?S7g}zdwxYZ*QqrM6l!uFekx37)isE%d5*6DA27O9 zR7mwGoaZ^wQMXG#T;@y3l%^wYQ|-Q*$+_axV81anF;AIBT2v*+ZN|%tI+dSGjVPtm z5{xMdKne$N)s2#$ppSu6m& zAWWU3)&AYqrVGH7GrDi9+e>=*kyxKL8??5ng-T{R%3N|-R_54kDoEU=s1Iz8O1K2; z9%r@|Yi8}OSL`{zhX<XRpOAEpze^R~`3R-d-w!NRZJTDbMWoVLxgU=q+T}8$ z^Jr>wZod4NWGFgt;@JvuYTN1zp=BWK8sPr`qyGS?rtwV7*yeVohn+schTj2uAhU2= z79>*vzh9o}lyy$iqga(T>$ZJDbC#t@y%IZ;RklM*M%~F)5A{wYrRMi?60NGrn<_rI z$2e`mgzo$MIZYDZ))9$I$ZYQb`+)%4OZPj8o5`M<~#5lM`#}w1)Qb8yVd1Ye& z4C7hSXGHfLX~l!L#cs2~rfdT*71Zj!#D40z^*gFHZlu=H93j<2jJ5nEFD)CJ_9bO0 z8LQBaa^hh za$?ec-;snSQ>$&qVvw>ox~7^6LCDHnRsy*Plgsf586=QI(CXiCNZD5QOd@VvPc45J zd(r7?PjPiYi5+F5MJbV0brHmN9*7j%EX5vcvb?s=QbP8}M)UhSl5z_2cY(s;g6GQp zEhLeA@4y{^?74Ve;~)cl)kM7=o78)rEhtCb8cgKHks-1Jp>8h)c=y3sImfoH#E;A5 z?pH&U<1WL6FT8v%wbS@Ds-8a%7e~4O1$L)TS-fx4Ztk7jBs~n7$aA*X`cQ0 zLH&nAeBEKqP*^4Vg1hC++$QFH|1rBI|=wPP8G%`nq1NlX7Pxkn*x_Wp~0Ee zD!0R$gjXcIOELZ&so72j)B}F7oM!~*ARhYYaYLMF@VP9CCsl5?v}w)5s!Oq`bLro2 z*4c5WP$oDDnInZW4aKa47QjwYf-I-{%F2+G5&}Z=jx|$UAG(oanX{K3iFGDlMjN@9RRVqCNO{&I zx{GpKFYH@sDJx!5PC`p(7zHHqdDk)GxMF9u+Ny%={0BMsu{>zh2?uYYF4wxZa$HT< zEhaioS+|q$f$1}+R2gPEOYI>^an_19;Gu1jK_q~9$k#ON7BIF~NGx>UqUs-=B!Td< z5&<0T)kCXRz1bR>(l#A!xv$K$*|+1wgi>9N@UO4ULx@NPAz-xdQoDkAz{a}>WfHSm z;--bz?+mU2HCy<%_X&nE~}NTB=kUE2+g$Qdv`cqsrVis34F^h)`01;Dmx_eL|_t z8cw89uF_kX1{9~H8;SO+Z9g%}qYb^}B`ZiuTNy!RWy}CTP#9MngQ>mxkT6Ce1*3&o zdXLl#p33TtC*fR`QJ3&;r7lH~h70L+&B+K})Olej3k4^(NzWP3lNyZCqE?(#>Do(g z*-NQiU%j4*Qj)Had5Wj9+T=Yx?PU(BD^|?;h0KC7m1j8#^&d|<=G@0L?=tN?&qWMc z`M3B!Xffjk^0{woN-S%hlTo5UjHV{E!}F0mxgE774=2t+WSATz8DXVsIgv0qM6rRVJgl%?js^Oh)abDrK!cXB>_f7_IduN?=9Vv3Y z>QixFbsnUpw(CZ)8F!3=Z!SO;j=XDvHWQ> z^=_3;Oj=a>f?ir8!*I6SE7+&qN|Uj&uHh$ovZ2qg#&SB36JtnZhmb!aytDdZc?^?4 z&-ESsg&qF@1tX^0@%rSOb=IdsrO!mfOOoS^E-YG2J*FRdO|ZOqMYJIsPV6a5LBfeq z#}VRlI!QJhxAQzNQ1FPp$jte0hF1s>-t6DXy z08=aR#a%BwE<1^B;^=531f`b>&{huh7aSmPrD&YINb*`T8r_F=P8W(h4pW9@qIs+S ze>n=ZRC?)KiA}fLYU1;oiwRL$ZkDAnE-E(_Y<5CWl{%A?!j!xWbH=%^`gBflItS_W z=(`tqtig=|{@Zi)>+@E#!-VUWwPd?VuGMMJL8uS4g$hIKZN{TLf|WY9$X?eR90HdT z6fi8hf zH9sY_E(Jx2J61B41h@$b&Uhm_kRXw24q?(j>a3TDS{$2Kua2&u(jYecX!F}t2M$n- z6lFg70Ue0XCyX6x#P+y?4$B?ve0w{Rj<)r->>F#yVdTFV<{OaO7D!Bn6g?|I!AgM{ z_8qa`I_a7lq;*-P=J!>n#LYD{x*M&d45TSILn`zua)t>Q`DcOh)<1{9?$Fp`vNNm|so2ru%H4&OS&xO^AVo#K%lm$BO{mLrFFq9z! z2L}#u+nRDnXbn8O*mBJX(MiOml96ggp{Oy)|6PxbpHTocI0r5c31wCW46ZT{rfKc3$!ZNmsqJ2 zW5JDdNu$q1xc2dId6hMWU2&j?)Q>4C1q1rh6ba*Y-0MHaAF4ko&aF#N!6CVR(?EuD zK3uE!8>wC(E8RJ{r^e}}r(x7!N@^obUDbuu6zfMN*HosC)Tsw%5Puf#I}G#fV<8?* zf-AAV#IAtECVOA%)Z%M;9q(b+ru)|@b8mDu+Ui$VsaGY*a$0vhghnpbsR#O-E)TjI)~YVhFBe{M=`DqU<`{B3w^RVf zDjl*hMbjJvGiV=+?C#xe>!GbQf5&cXUz=Mok@9Zr?Z7B%cZ_Exj8#>agAIE zAu1z;Opijbq4dhYf2Wm4D`|Nv6^K&mA*n5+}4pqSLQ^O`%n&w>>tE2HB>@oQ@Dkc zhC8TlKeIP1fQ#gpZG4t-pgg$Z(?^gV>&X`*+t8o6IcB9IrQP6<3M?=-{Z#bty^lM%n;j*2}na|8-hZPFrkz5$tT}L%b3w% zH@R`#7l*oBEw@@02>{w`iN+|55MH5GuvR`^IB(1iIZ3$@{Ih5}CYmUpE zk&Cb{*P(bXg~^)Z>aYdygHxk-E2=t+9Jr6#k$hT`j0T z6zq?KsjQ_T0hK(Ea*gQ(eh@p5qID7o)WC;h+U+yyAoT*M{JWmvNIJpb8ed+zQ)XU$ zHmXyVcfnvPp+@shkPx7i`7zg?3q&3kGP0!-q~Ir3MAt&iP4ynat!Ma*jmXIn-L}I}FZ> zPS<|@mY3OF+;&LbPT%L?zLUV}B5HO-2^DJ3u1sVtPA}o(t;~$2WwM14y(KEaN_+kh z$k3S{A&kOY&K8Uw4V3o);lIw8%Rd&EntHp|xbU7erlZ^LyGn5qB*t~sy5oV}?JNL| zia~2>DNolJ)%em3mJ=5~=scJ_iGwHLa!2WDg1_N@%ebtz?n@$NS?8Q_36z@5#+A7{ z!d*!yX+Bzk?s+^YV~}-^27Io`@-hGyV{83aL6zW;3@^1|xS9abt;b$Egd6KEwL0FF zZ_sK>hZw|)?4p>C6{V(&o?0`W%TQ#Ur?61ZIo9`(B6EiS06){&afVX%w(I1dJSy~N zuhzTX<7$TFcns6%Qa2ee(J3LP{{W(&Lhv_jb!rP9prnE@bl?(pRz%R^Y^Sdfejls8 z9eQS%HA;+m4Oi;S{rY3R#D%6jb*LbKvdYkvJPNof3kku-MxD(q8>TG{9NHTAb%#Eq zenyQB9BIi@>^`?VN{R9cPShbpsR1AZ$<`a5?1utE z`YXfyJ0HOD9LRlLN!T4-zhzYK2IWA8>>)0s{>3(2hQ{Y3IPpq%Z%S2wz1Z5Kk`6yD z9$RN+<^C&-_CDKW@wWT?x}tYV(%cFZxR1zGX}=1m7a=Rckm^(wobmWVigEJJf{}*o z4y(HGMhtvY5j5)G6af+tLnI@Q0@q@=n@}86PqdxxL#=? z#2k7^+^&AVULGNCHmQ`;QhUOeN9os7q*Um!-j8q1kin5oY40iKh{<`j*Mbs-5;m`r zo!yS!Wh7)?l9X;Il`p!f(K?3BA^Hp|O|;_@Qs9)#iBGx^N_Tm#NOi#G%x(oKM`#f8d`J63SY3mQem=2 z7CE5pTy#WBp843wTu5j)&F*0%GQA^#T%U>k74zpyEMp&4wWniMW8820 zpe1^>S?SdUx{D}*GDI4jSqNsM5s6XKuO>r4mR&-UNF))Q;NYC`jrX%tOG*|QjyuGS z0M~uf70co#?CL0Wy4B4hW2tXq9jL2nN_!M-M*v{(0#5({02&RrtZA^dW}Dma zO8hK!A}32L)$057DRqaJ6)^Wxs_Uo8jMIwCo?oHHo!kZqa4!y78@KI zY@!X1*UHr{>89DX-Fi%}nAPe@r+giLn8WIi9p{2d!y|GKwFMATf>EA89Ah$n3&+Tr zvp&OzP_=RVMrd2)FpVd_PuWDenC62*sY58eXjg;uSKgK82N6zZK2X{Y(08e6 zIV9mJ9@)|Di%gsFsFGk}@`Br-Iq@=_;Y9TzG`VsBtUy!0$x%J}nBF$o7VJx^h1K4t zMYw78%C)ueo_jSYHCNX>p^*Ddi7Rse7oSq!SxOQcO2JAJl#n%#;!N}gy}J&|ap*2< znrNG``ux)^JD{~kI@rU_E;?!QY6)C;A80Nyaggdx)jEyEqPzeI$xiOvV_A^pMroe^ z06&7*o$QV>{arpP()GunR|R*aNrvscOO)DR5gr;UE-lo&REJ)a97+Lw)TAXTZNQYP zDp%qGIywk)qKuhnjp&ZYiwiax%kJ5d|hHRLV>+I3vNu!F5O_*)1aun>Q*;5EnLQXEx%_Emo2mC|ZWl}xhivs;~TNvN(<)fSuh zPcb_RooPxc+_D>O0SU$e$-xOywO(k8Mb(r~he-Cx<=)4#XOnb7c1=E`GUlz^wZP+_ z875P1sZpumfMrD`f{B|$4r)GLhS064;Pr+AsnKWD97FOQm2O%x5+FeSZf zpOQ~P>suG2(<3Df2OP}e4R9-+Eg)`~!j!{+q=2D<2l-f(k`hIW=9gpP zo+&&LX(S%k)7b%f(NnKgZKT#NT9TzrsZ=&cj;9iUl99dF3q!CQ(vVNOjyr1HXf!&2 zpb#1PCRXZutdfUz9cH0OtTuxpL8HwoOo-dm8+Xz`QAj+HakQU&Xu0BR*~a6l&BdMZ zybC&eD=*X=#W(wXEOr#v>kUJS<5J~FQCsdhlHzwPtJF6A+HeWMN$d#Gegy4VVU86` z5Bk0^&kB-O9gTirMmp;mgmmr+b=1YF{8DNxE#g~PU?jAZpdZKPEm_KV0ituR!^IzZ zS!>My0Hq=F%jF}Vk00czCEL*?Nm?L5hq{94 zv=-=fe?Dz4H=g55$xF22pIKWjgp~P3Io#8jPC+RkoNK3tQ(H>{N_&pVv3Re&skbf0 zBT*bvwB;x`g%oX4uunUGKk?RAh)f=IwP@i*pxIEKnb4Vx!`0fR8K%P<&i*$a_4$2t zJPi$QxA3f;#m>;)RCcLQV)wo#N_o{b#J5Ooz@5HY5{;+;XR<&@{D!gRlg*I5YR1nk zfvQDU zoXbV&DS1d*TaM^Ek+%dXTYyLeVDpdxIwhFT$&Nza8q!bbw0u3M?G1glF~r_t@o{D@GfvWu&vw6!Hu5R;Iiq=KXDN^nAgNXI8!yll|L>4G?(b(S{ks0Z<_ zls5e9cUb6_MC;z;ue2Np{unsuvFm+n6BHu^v z2sA5Jr4iOrWiD5oU4BX$Xg9DY9=4W(bN!+{usP9jJODzAw<^Tg77tbIexKa;TM^Bp zZ`Gs6D5gk`hN=(wN?WKQXaP(PR-skc^C9p@+P+~I$jPxA;LDV198tMBRps=KBXRt($G4wBFJgv z!mT}1h`(IO{&JQc`K$$g(DuhT8116=944|<_B|?t*1rii-MiDY`4`opQ)cT-XtG`| zPGlw2KKyi*9gg`U0SzgzS`zCC1WnhX?mmg(ZKksTK;M;IyL0PJBbx>^P;Xa^y`N z*W?G5!%>@k*@p>E*O@6QT0#+ll_aDoXDQr4gz!g@eSEDfFAzPwI! zZ>ZfQrO>WcDh@6@=RBEp#0az2@kZs#_@=^|Lyjo=LXf70#J1`Zj5wU=MEFt%wYOgn z)pRe&!pv*Wm|J6UWF5HMg+XinBJL@ot4&PROr<=BVjxLj4VRfDfLuaKk`z;nfT95> z1n_m&JH@4urHaq&`zC%LD@=1ACv{0q=8=*FRDvfCo z8kCQ;D-`qxaV1Gx+gk&0&g@`?5ReGtI6CrA8OoRKS{m(}^j}r~07v+1aXcZj&}*b1 zp5zV(z?=E5eQ>?$Ojyfpb!5?IGYt^oC^S;GUk7mxr6i4qxOE$nps!++jlT(%(zip# z?fklY&>z(i2%70%V3YJJqx9>g^**f2g-U?>zCKIxl(v+dHpF%rT!-FLzDY_I?c9O# z*G(BN$nwCgt$7rf?Ee6!oR_%XqBcb@1imTmKMtKorN%Sge$J}8hU!opC2463Q2X@% z0A#0jPnOc0YNz3jsXW9#*T&lYXgtXXJtY5X^eN<=tZVJtM%RoP?K(2Z&Rbv{t@IE z@*YrSrx1ql+5*5NC%>@CAYk%!nf7NgM>_dhzx4)4#xS>!lC<}~Uiw#XO07(hU+Oe= z>NEnXZ7z>4JZf`qg4$4+r49Ls--U9bq5_Yk`f-=#17Npt_^z?DSQ=#5fPL%Oj=hyl z>xWZYs&z%$m8~X0hCUviQ!UdaY+>@!}uwWQv4d-ooT;6oHj)2d-l}G$SXB>yp*(*0&tL&scTLScu79l z?Vxe|TG^*2%ZK6?mxzB)lQEMJfX8>}Pw0wX39JNoeYkp^7VWsLSd(R@mlh(Qo#jW8 z!kcyT0p0bVO56D@(FsEF*2mKavo?7a`621ioP7 zVO#cC@XO$eGcbCK=D8=sOcfe*CC+jBcLOIw#f|B`%9ya-~j^!k?cV)P@5%SWfJ2Ad(8P zkCD~5IUi|bjd8L+H^g4tmMC*>l}}~jpu!wOfGh6zdc7*h1duRzI>qsK z$rLSgXRRvy3pMgjJ3-P&v0XdW@Rs=YwP0DjcXDKQDNrL+p*HH{`6aZeZ78Jd^6-#K zN_gWq)xHTMpN{4@-jcEZ0I6C30IFob?Dmhr0NRe+x*HN*X+B%~odrn)0I2W}i=>?}+V%?jc$vY&K%?Nx>0_p4P^ zNC}xzX`61E*^-p4zl<50q_$4w1+g6nQBME_?(Uq)jxA|chJwOLqCPwP$LgHAi+MjQ zq|};IZzWMGmmIp&jyaVrX^#pVHaBCiN{pOm>8X?H)7?=*>?uEk`n@`auA@(#P-UXH zF=8~^iV7<#bxR~;7#@%@j!Ly;G}2sEQf?_j?u(6!rjdWXm%xC+P?3g$i|(mOz(6Ez z+E58OIM3lY)h{+}T@V^5?4$h-yPJ(a$(q#qfZc^R8ESQ5KiW${K&v0!&*iBDYGY%% zv2R-x$elfH6j^cn<@FMYQlkYeVnS6ZDr!S%K^X}PWh&#GCa13s>E!9Elu8tc;j{tf1uQy~g0b7sqCq?npK+*>x<`ZqjJXde1{fY=K)9z6 zpH=`lB%Mao08-wTvfJjY6yvQFvXv=pk+}`z?pD=$RtE&6~&nPr(2Z#t9fK+Rd0LmwVroUUj~K?oke-7vYd8~?J4(UMJg<+OG(;F zLxVU`BpihR5)bE~vgB+G^BffM-=V~nb8Tzp-?CQ;$rM*7R34ulgvqD49(gGaAzO%6 z0#Gr6K?f-(whp-rSfh9nG=M?AIs<=R%Ss934K06P!4o>A*2+~{o7CHNmgmdoL7lp}O z>Z2DmJ{gg4s$a#k9-kkE)SeKOHlMItNFqFq&cq9;vy9NRJ4tX_|% z3}G#xqeN1(Q}jsYVZPClRDbP3s5xKpLbq)4Jw zrq4`NM4ufkk5ZjeWT?2}FrBzg2q35*T5t%-6v{O)g?tVSk*>a|qt=)Ybkc_4sJR(6 zTACKjc+9ISE&IB@`%(cI9rqAB1FT$NG9T&Ty!=;9o(?R2u3g9Oq&^(HSKi$Qs<#4x zS8*1|bV_!SDb+3$jwuP;cBJ7YKmtlg83lS}Dtk61n4dxXV z%C}-s+U90ZS=s#sdq|zzkd35^a zNm5sYAbY7m1A*Bo$?vM#?rlCpqD zbGI2Ml0v>*NN|Ih+MJ-VD%gD`^c6PW;b{E+XSZ)}mY9p>QFM-e96FgqYWRmvyaO|> zqa~RNZgEjWalI|Ppi(yl7S)}}AwzCPNEyn=^KoR4CmhiSb*~76KOS5xrs`{l9^p+q zRrq-74La_rF;0Uv@3rm9bY!(yiwLc4)0|U+D~kvpc%LmF)}$PS9mEunI(agD+H;o~ zi-6of=-I~~O_470>V#{LsW&8u6ta3%X~CpZDlSfE%5qyV+iVm7k>&zqHa4vUr6FtG z!+`6Xp4})n%HJ&@Sm>yY=XzA{tB$E(tI1TVol;WfNpWf_C2CPT5_5nENFKlet!k~5 zNwaEqXHaP?=soLj%%;ViP>Wclw;50G-iAk*UO*`zgs*!+Sm%L)G{s11(nnPNZge`8 z)VuDBPqn2gJC~Y5t;$nt^F9^gNO=<7Unq|qNq83kQrt^vP){U?6K0c96h~AwzO9AW zw|#Ek`$ZE)E_2WoCMYRG%4tOkQciP>g?^a%>G;`H?@6TZZ(Nb7)W3&)q$QJ`s0j&D z@&F{B`2PUsq@(Vy?}V zZg^)Z#xq%u%DQ zEj5eTGAc~vUu9arPI4$n&L4Rz@__^rcen@lHCCxl-E9O$n49;Fl}ImchP(dLF6UdP z)o8T2RYz9_G`GSW4U!a8v?CZfSEt*yGC9%Bcmr~60_KwK(QmD)Jwu;qS0UHqL78j9 zc@IO40Wpj~@0Jp_#=wWb!h+PL?%Y8+2Up+%B{#CGJ;TcyckZFJey>gbVal-WiiF74 zYmW&v336ZEGP3GZf#($ADQFStWj>MI?mFmQC4dJ-&#{y&^;OR1l$WZ1dgE?|x>5jF zqz*VI+b8taY=_i~j1mnks>Xdri0P`huZD)%TzJS(N&=4nfH=qR(w(j`A2Wf`P6xC| z1bl6yD5e}WG=+YrrXF}E*$Nb z`*rtr`E*S&Z8?`>V%&8rT9ec(EtRT~Ql(a!arfe_X%0q^+p1RNAw)RPQ)(DeuyPfx zPwCjPvZZtqw#$acxAU?G#2m?FY*G$I{7Q-SL&K*{t_upYa&(3OwyM!$xT%)>wJqf( zXu(rpI7*V>%2YB+7Lo|T*7kRSc~QDpM(w|!`CP_M5NIxHr4guqY)y+yr$$9;y(Pee zQ=qirkfoE#KtLX$&!lHuQ5{w-Ep6VG*RB?7Q(46}6g8N#rc_&XG1yYLQWoaZu|N)Y zV`%SX@0%Bi+!y!L+IAH93Y6B1aFmV5o#gG# z!CX))lt}F=mvF>gNto>NVs~rpmGx6EscZ`kev1y z*1>L*N{2sDRwjqk=+*OEu`Y*V)?1Js__kKsk>Ga|B7!7MaqZOC zY!VwTl~Ait*m7M;Jm|6-1L0JKt7yj~dFLarAbSl-qT9Nlp2^?AM^Gxg3-Li3lT2Yk zY^G+@3LkJM;#9PG(bLGn3X4cidjh=URJ8v9prW92TJfw{Ur2l~bZf)+RjoR|PDHwd zMEb<)Th#Qm1cLLTD$=AE0)bn~4LFp7NZK3Z;{!t%hdb1!BQnNZ(PVzV&6Ovx`h8XD zx+l~wx+J{&56rWfbBp*=nOsJg6f)F<`wEG>bi|J{?xzgGV<3VjH zq{N~>8OG*ClPTi+g<(LWcGZ#PuLUaQN>EWF1Pu$1;u2y^91fw!9Xg`CPr+gFTyG{u zhLCJg)ui*^gTWn^IyKXJ7f*V3)w=y=nIO%Y{{ZuLmkq@wa#>WAho5~eD1@Xo(n#~k z0~kCj)2`#~jr%jQqdS@nKK}sAUQHi`IhoP;Yntr?Ti;!(fU~d%zZ8d_2cLsM>ebI* zMI9A5RLTs9FqI+Q%rzoPlF%+34dcoWVHo7#&$FdK&t4u%zqGWbdnJ5L>_zJe#Z9sDsq&$R;q*r?se`m zvRAoS;A8?xCjfq9K%V7jv=gvjO726_&kS8E>6cIMJAL)u5vj_mR^?M)Sd$&~r_Nh% zp#X0?-3@|VM%1K&pa2IOL70*P?%~L03_*`~AZ_p7`dR__uXcxWQ*BPB*w%Yg%SreR zQ0KsGfYf=-r9p)_8o~ivAcPT+pvlfiIe109#^b^R#Q|s&04d$LzQ{do^7$vAj0bYKsaog1P*)Sfk5eytm6;Bm4)~i9hL}ldvjLY? z9fkVR({DJ9-*=xu3RcmK9B?RigJMeWKB%7DEx5dYIyl4xf*Zx|P=m#^tFqxRTDWCG zx?u=ydhX_dQKZ&T$NbdUiKHuPh?9;|Ye;{za%%pGZv2PinEm5nU~*VQU+ z+K*6*B*S`5VoLo*l$MfFlYmr^qDFp0^~S3&u2HPPGXVA-XSMJ12!Y|*%B_*tYc;_d zqXf*TwE=5HXAt3O^W?08K*l$27#-8B-wD)JnxtAhRfy3Zs;2tSE_aHu9S) zSaTnI7v!NO#9>L;kO0nslgw-M2Ksxg>{#$+#x9alAJA6FCrf?G-IYjgsG!_hXpq!0 zl>ny$j)xVIj=_1sC!C*Qsr*(~D~%SHaMhyDVv@oeflzcI$pw2!^1I8} zg2+||K1D|ZIl=9z1ruvGHLhh}?XISW(@k(COK}S-TflLEvM^MA$Q)>hqVpe4;Zr1q zg2yUx;t{s1HchJSJ=e`X-h?S}Q6$$#{qcu(V1{Htqx~JR8o>i ze^m2uROq+IQAO=|N^9d)OMr(V!9&qwhYUM=MT8 zmj3`qwFj|jr|l?)9ZiUAKJucsRZ~7vM{&JsNzM-35Tucw-rCB@05pzK5&EfE4xV*l zL&~Yt>(u*Z=bcMwQ)MdTs5u2nWdJA5VF0!rAxKHa-RV)~vXuoMaK_wn(AMpH4bJHJ z6S{R*s6w{sBH5DZgD$5`kGec(6r7Yse7S(}+?;xM4^hXywI$7b zzu7GT#2=>@@Cb8{j>Zotn;!%)(|(w&J? zy&*+@rEN&Y1~de4$BXw|N%uC4V;?CS8c-ggbmFPd+v*i9brT}jlKT>>O+u2Sy9Ekg zt}K@u))NlyY#6B&-tfcUNVLL&E<6QsGh9L6rihM&7Dr zN}&2*d&*y_v`A9WekGJE3rCz3Q;cMz)2w5emcm1u%IRY8yg8iH8?L?gub#yUE>dWy(tINYP$;Cq~Cw@h5JbggVi?twCT(4{3`avdop zIs8f)`QQyvx{zJ&7Xx*eDRT;JI096k#kBWMeevz|I%`O!^-BCYMTYb*v*5^?Rb(=k zWHG(i=|jOvd7^&;lu@^E&QhhMaj2RlIG`y)>o*Nj>YB^-InUG|ZKN>T-&s*ZX&6dJ z$PGb}wVO04$t&eH^Jz>9qx9E)8+j>fl&9NqJ@NYLYOacRNqR)ON~NJ@I_WMqQdggZ z2ctHim8BUuTDQ5o2LRxaomTa0Nvj@s*h+CKvc{vnkfD>-?q?cA*F{MLAWESYj}#*=#Pc_Gi{k%n$*QlvfVYsN@gf4uEBA|`3PkI5UDIqY__1_2|^x8Ss)`jzA53D zm=ix0j&q3>W}Bhc>eM=oJA@a5W@YBV9(;{!S`FzI?=iJweTd%LeZs0i>=l*zC z;rN?;MbFh4jpK5{Y_uLfFyfnawQk&uXSn&~YPlm4G_)h?r1 z^JGbsf@!IF*s6l!GML_5ZzUy4bd@NPw1siba~8Bv4(Oc7b-1+Erf#A2GQB|P{A*GA z+G=f0g&H))N2&Zm0SgN)ts966NJ?|^SH3~iJhqnyQg=w=%_UbEDcI>xet17IqSY$S z$Ds;efQ3$J3=~x^WIF5T`qZfkEr!6yDIozwMViV3pwJLP=yc7;{mfHve`{O)kH4)9JM)yYMxu<}C6;LP7dP>|> zg{jw_S#@qGzh}Kuc{^_cH~wXRtyLfT8Yr)8Co7 zP#{KVZkewhj6JP)S&Gc9rZTCdODDj zWmC6dB@a5m(oeEFMS0cSTsCG+Xg1_}bR{MvQMe6_g*fVvpGf_)laq~WVzQiCO|1Nx z41f~aUq3!E+Ik9G`?95a$REEW^Y_tXvdu1}*MOjG&4Jp8s1p=>Zj02OZrw~ z#gZ_ZY2&8*Za-A}(5sSPSWVeXk4kclNv_%{#1%SE!%Agqb#1q>jFP40C)p_(9OGFS z{u2KH32ZqJ=<$C8vLibpIb6w}4%}CB-`FT+`4LfTG%K>3_f;7wL@J{@RM?Qym*N$2V7OsqJRf)%v4u=+^K zc~A#w&o~Fiyhj-0Wyu&D0&C#8nP4oG_O)p*n{u2{YF@9y`x+g@(xj?eo79SY(w(zo zDQE>tLY9@3sX&wF1Hl032-<81D}z{0kZDdSy+ftbZOA_rAra!KX$d}2ak&0kf!G3f zZ6OQ}IKowtfv(N;+ND4$w_p8nqETy57Y0)=rdm}U)W%lk7PYh#;zMH~1-PXtN%Z>= zR5PlinS;~aLC1ST3&w*Ie?lH+5}0aTqjsr-4*(Y6)f-wA6Sxh*53&yffav*a0#<B0n8dxs#XAk1 z(}#@Clu4pZqTaA@sBXfI3Qv@^Y>whmM0KDj1s2wXZ3h_3YUN$X{vio#grkI{8`wjh zo^?t+9*FyLXCbL8U-Wc4l>{C$oO@@H`?Z}Lz;5Vb6v{nTmsqIL>h9DYk6VJU^EJrZ z68v>!VPP1u; z=6OlULXVc&C{f^&ImUp>8Lewsix7G4O#$&ljEo4Gt1?2}=m0L!?)mXj#0$mSZBb>K z>{v+hnu8M)wG#a31B&KasL33 z4pxXDX`3hDVVWej$M&i6Da`H}$ z#(~ii=NtCyvU75vpV13;@8AAU?ZT!WJS_`fr}hs{`eAJH_ z-~v|Tg$p34fD({00MVLB-DEw&sZ$DFxVf;t@(YD)QA;ki@J{pc+Cj+qs9+DCm@uL2 z@}>PN=?!A&z9`i9XRg(cDq~G5s`6L;7?ll+DNm~bTTVwHdb@*_O-ew*>PywZoiU(-ZZQ8!@cQApjRrgM@$aPvCO5 z)LxC-^^TKQYBvM1nQ~2Xms54`imDYQDh{+98@DF}1{I8q6pi`aq2ai=@y6DZ$0z>) zFNZ<9wfq99wCdzOjC5X&6+G1D15lLS3KryrF99kY zz-=fABa9HQeCyYuEb!bm*WPyj02SeLI!x@x`Iola{yz=Tcc3>Rt#ta2Ro)$uEUd^U z@p;Ks)sLn&jC~HZ@FerG+TqFNV&}BQIRk*U@wFa3)#0Yqp4)DGMW=JB3cR&oHyU(x zxR00sI>M93{{SvO#~Suz3;U#B&xO=@E<6Jn^F}>)PTc%Q=BTs?>4dXWM5RZQ2&KkW zgSBPQeIyZ$xHus9&O2+IEd*}2TH?|OQX7WrzAwR5yKB`M)oJy==+D&V0JTU$ak&9r z$0<%g1A(0L%{oL)*ic5f(qt0%n<_rV@m{4{(k*dQlACfv>3T#2FAcm>a+0C%wB&*8 zNjhNGld88-bn-SoBK$w)(v7f_HAP6^76I}@gPp+u{>G@v~%zS63t z78|kOZfk*EH6*X^$o}frYab?Zhc7P$UNdC0hy4=gHTVMS~}a<-O7oMA_eU>lvBRcwQR}Z90I` zEKn3T{{RY*Jc^AjTOg{I%|*gh@$+4b;+=4v#YGzw;?Clw6@-Fv06b@2nlakY7}3J= z6Ovr_NJ%8_QVyo|D)N{hF?Y8XL^^wBB`L_!6COKEo>Yc|Uv>c_a*&~&#HfHtCQbo{ zp3&@yhbmAHmhwJnjlQDWsf__Jsbw`3NAl!4TVYFLhtl@0rFm8)@4Wq1Rqs)DKs_*3>{5{6k#t z^rTH-mU%ZD0Jr}Dta1y4Skd#lzPknUcA;>vitM=*^r?t$yrm(akbs1r?19_#`Rkx@ z1;n?7$S@EEqwj^=PG?*ChZ2KFmkyHaZJBasPIX9WmQbKE=?YO=ih@&sa#ivgqD+yD z-AAg?!oZV0O)MJ?&-hp3Plw){S~ktyQ>668`KJe?YhL48ZRiMh7_jKx7{vm zN*h7W73FDhgz zl!GDmR@n&;X8@zZ&S!NoFHIuPxpf79*DdAwES z(wkvMbd{wFdvPyH3P|CS*e(?CQ-YpP1h#lqS;ZNSZ86R*2FB!jbM^TpE>tX##to1y zW@m&NlTj4o)iKePC z)fZ5DROZywRJ5c9*4e`HuDaK;o6BJkwjCRr7nFZ(y}* zw+eewtxBYc(<3B?WkZ~X{wc1?O4xm*>|PEE9NG!vDH$U|$k#?oPSmtmTPs7mr;fbz zp5(Q zrrr7wamUd2{IRT=0sZ304Jk)^NvE*#X$yvbU z@G@|5gM*tUh);65ZwJKtR!c`gxmVizw|W)g8Ha6(&9zCQT)tRSRVpBDnb3$&rAi6( ztYBoe;N%SP!5q9^|Vp<{&2X)_+W=4%aPn4s<{%nhf3(> zvYHjUL8n`m?LDPzVj2T1paGoVej-TaO3I1kldO>=-1-9TbsuAigH!k&7tSl^skF=M zsM@edTTi5ufaiHOKgj@)Ygj|6e#ic8V5>zMp{=@29*K|B-1v# z8XROa+lxZh+Lg5dATP^tBR%~fops;Ro-X_xhUJl~N$c2(KR(No{;u$t^5Od-Izz`z zw+6?{x}GuONs48SXGyqj8c>UJq(pV-Vd`v!&{^|hp$#zFb~hm}xg&DcpcLCI?H~-N zz3~bBK5VDY47Sng7j|4|kZclu1l9akAK~LF3`W5$T2BV3(?-CGpgHU|3cC2q>jYk) z-}enS`KqgOuTHMWOtzCzOy+~A1(!Cu0NuM{30GoLRg=3_c)yEdWcXwrA04^To7F%H zt-$N}4iKIn;S*x`l-bT82?c4~_1M|{IkjIX@g>$OO-F|n`LfomA(-u{#}9QVJK^tsqZ<-cflo>rWylTm=Q&B~%MR{gT zH4lYlYDn6qmH|rJQ9FS7WbPfctBIEuL}FM?wEqAr<7+P`9q~BFAfgmD?7CuCUWX-y zR@2R)O*(=xlvKU--?O*6Y$Ul+MDx_zsU-MeM8TRAzfD607LN=6iUO1TG8PzKj% zifsdi)VB|8_8N&%D#!R4WyxM7Eyf!WvZ&L8rd$t=Z7K2z1hwz#0B1ZCsF8an2A9?u z(Njf8HJhadQd5x3x}%9hW8C>^QCH?p28?SQ@4C{VEbVUYa33`Sjdj|$mB`I8%c50T z?dNyGz;Q89f4uU}cAiE;aDI9?!7OamqP}Y_lf^5j%Xiy_EUI+UrvYudOp!>9Ol)Pz zlL-Zr$LuLVvUA%c=ift&mR93*S;BE}Eh4+$=%Bq*Vhz`7R_&T~#4ZZ!QG~U@j_z1f zEvY_ZXYe+Kta?$jek^mX9}jEYFnfok51eC)BG7HtzHvyiRP{&gDN3hDr@Er-Nb%;S z;J!}Kr4C2Po`qLWUq!q%H06342p{pl5=^lPfD+;Qp`l{wT=D=eB{#Y(Bi zVJxuDtFN8w@?xC*3o@S6h5i!!S15;9q;Fr}`u6_{bD z$&i;yBYAFQmk?B^UD&MbQUC;iHM{*fOW}|=n-;qaU>L^%+O146WZK z3LgC9Ir(Q^jK&OhUsa?30BO6Rb*w|P<(QMc|H?WJy0Bqz;JBYO(;I-j2?QooLyHxKO?@74pMHq^%=MpRWiG1S7eHvE>qB^w;Z1#ZWQ^bN>p$bppE;sWEA5BkVd($ z>Ndk9zi5TmdmoC=&vSKaVL~N!s^Gf%e9&ECb$8UHxR{8QVC!J*%YksOs z*&SL(RVB3VcWXT|>U#>GLV;bY+ONZ_z@I6|4*9U$XtJVvNszS2eWWyT%W2)p5;bg| zw(ZKXt}Sb{f%=bvEcKJ2jdXXWeJkoUp-GcQh~*i&1x>b@B7CXuFLZUN1)(@|B|dOD z%WdR#(T!k%!M_ix0xA5*IMr{r!ANfoiOIV98Ci{b%!r8yLZ>>0i|L69K|`gbsbG!8 zC0I(;xDeqUp4u-WHpv-lyM8FWB!ya{czU#~-whOMrS^}ruS=4ob74|J+Jpp-#OPz5%!if}xZB(0 zwO!%zV#FK=BJ26el-$>l>J*13DZ>iUi=QQ>Cu9Xzo{~L8Ho=ox*&|dknI~f5f5yI0Ti1fJgwSgU@Kp_@lDcjk+g+ zvgHx#A-zf?#=7hqdSnJ8R^?YE4Z(_aC8Q-Xl#zuk*8+B>wCBEXG464!ig`BSM6RF) z2I&UCO0LUBrPOMB5~i$EL#zZwr$Ti>)WyaDQ_B0q?f|3&?EyUCZ9xJ4XTZaK3`W|h%EuRJzxk-&fq_ztVLy3@&KrU)t3fthQNr zAM0VVa-#0iw1-xtfEIS7oGCp^a3qpDAYW@)uFr}$Z0)R z(Ge4Biz!@Wj0Cdc)yOIRl6c#WMgi9^m4fCxy@H73F2@hVV9bm|lztBV5AKdWHhdMq z@i}WRsog4ZwOt{DDpe(=ZDz2XZrR=odr>bav_u zsZOU=s21gkIm_mQNufl3wLX}HhSM?ez4SJ-oP@1ONF-+{Ub-gPFnkgs=iaqzj*DYa^}sZ&^$0Fu~Y zQd-!Br6+RAcMn>>3P4VO5zdW)ypn>Q;0v_#Sb=odokXcBpw#Hpsh(u^W(0#Bw5?;X z2|i-SBg;a$T7V<~b!V7H%5mv?L)bwFaC?sb00m+x7TrGDvV~rwxr(K3N|6#QrJ$lL zc1ZIjdci(mSxOVIfEEeoZlL36pa9)Qu3M5U!u?u(N}XP>27}E>p68q8$Vo|UX(=ON zM%3*}aF9|4FgT`07e-@gq(oA-IU6AtNh+JUCd$)MaON@z@6z z3cdMPA0eY#4m&+Z?{>YFE|OEQJA4(D@V6qyv}U8J7nHfHn%t*pv?SA`nGl(CY7*nl zExhGGJGCJof$BLVfvzw5k1AP5*&qVBJN_R9=pWM_9>x#1On0&cj-CEHs0WC2^!usa zB|42-x~}Oo`b{|u)8bR$v`m>28j6$zWn&0JTm&nEtc45$LD2ph9~L7T(a!$>il@e0 z$+P5fb=41`KyIj5=!0-hsZwYa8*YT*X-I`rN%I*iN2_jmEpJM&PpASnbFHR=0_Pt< z?4ov^-Bhsd1k@>yc`^}});Zd=`=sOBfyn28Mxf>g>{a;rGGjl?jPLoYQ4_~S=R~2> zVbf&Qsp?^r$B9mbA*Numg(qsE+CRppssW`*aNm*0rA%8y&kSB*$ev5 zNv&NJ^9ORx9NhFSj|WnA1WILY~-EI3xl>kgj>!q>g)PaqYN5yM9r|=<8(azI9^uZP{A3;3H^UV!2{+`t(L>W zvl=ROKXnQ4>D5{VmDI%7uPCon!%_D{T3#)s5>T+D7eF4g92Akk!Qg{}IcePaTT8R> zxgo@xT!W^^-E-@&iEF2iUPy$*`00~GO0m&qtLmj?G z?d3XI8v^#bVe6TI$>m8u%td5y&HC9N@LC?*CWE*pn&3nKw5}GRk=6>F9jf{ zkn!>hq;qSJ&eo1jD2gUXPu@y=70Iw)>ilYNQmOK)w&aGEW7Fd;NKBd70fyWu=W4P* zi<9O6{ppcsRI^ls6>`+?UxWEjpEc&?zII zm^tTLa7-p(a>&cab~Mgox_(M!4#DX0>D|Lrx#ZR={YRP(thnS9;Gg+XO zJu#-#l&NWLXKO&D94zl89B^_oo0B7S*bAocZw$zaYIB2o*5~2aA9QAJRIZafY}VmK zYT0_8@Oq5UT3m6Zg=J2>4tK52%PP)O>Ful&avHViZ^w<%`Fdy`m%q6_>S@%k71M zyguHKR;JV5cW08OR)V4ic8$PukEa^ahZZ=+ux`28yi!?BJ7A)BjnzY`S@!FcD|par zG|6j4N@&^a?jC~1wP9=_=N;g_iuThjcc z+t8Bh(qtg5Gua$OX&@IC?r;Z|4+QY9N_&y3Tr6&=jFRhD=I^|jV!&M?sfLd_6YeF| zCZzLgkb9*|cpRi~PR+hq$-x*P(AEG^1^X&H)jqR8pgi-g)CEdF;Rz~Iin!yI0CxP3 z`D)@q9GW*N?VkAV{S0ZY5{6W(T&SacI97Or1$x2 zr(8;A8QcgONg~Hjd_G_Ig{x4zskWS{)EI4-mnlRbsUT%bZ6t*_5(Y^~BaeRC1^L*~ z${~BeasF<#BJj+~p*a!8bdTr9=#upQz?0NU+`3|9w3Z`A__FF0wdFg~0uqm(sGMW6 zRCH^$3p8^|$ar3;R(vt_3Y#9L^*&t&>v2uTQ%`}18`+iZRurBV0ZM>9h{)G5;<)1} zzH4@K7hm9cKW31^cSPW*%L7~)x`j5pEx+UT6+UoxRhwhnHD-Z_6QP~sLAobAhHDo#1)JnNx$Gt7nld#Ii-WIivAMU5C^u_JW~w-3kT z*W##O@{L$f`eouZQD7WHsL`TNLOisg2`VljNk~tyDBzxP-&)ZPmn)x;+=&|I#u-fm zZlqtR`<}F;z6WQ{YpyGaNG_sO%5#ZBQMg-$DoU^jBOC&Ii@H77asw3H7 ze;g2M_V0zc^|mUKBGxI=pv*#;l0&H>(AvOKPd=A_hPaG4nJ!afbr9>=`!2)8r@UDl z&9qU!n)%ymPiv`m?cl4bMOL?bvc!252B)}{G!q?4ap3ouLYzvQ-hh<*o_mdVxcGtr zrVs#LX_1s=Hzkr$)^AHXDNv?RVYSn_wyooEvY=^F>QY~mPs<@jL1AgxMN)*CRc2ghvk?1H-dkvpJt=o;h{zvYWNSzp-j-C2 z40&ibO5gZG@a5Bfuh^9uk5Hz}6J+mZo~YFX#A*scw)v}BN`X;d_WcP1kV)1qW^9nj zp@U$$zY6epb1}@a6Mo$X?tq#Mb)PBd@>*8cp~`QN)P~M7 zoRFlHID$~Hb)k=tG8@>ANAse_@edDv3;VF}f1O7JAyH+-?#f8oaCq!=TF6}(P)d>& zou}L$MxazmH}ux~p;%F)Tr`Rk)sCdo-bBci32(h3GF;CK*x5h}0a?Py!B08PvuDSA z;Kt+WKO(lVCdI{Qnu(FTUhVk&ekl)9`oDekj^Jvcd`%C}h|p<*>HsNd05*Vgl#FQ1 zXq%4{VQH`~ubufoWlnNuGrR!fw%lxnbrzzUvwswyErot1M@mLV%wT_(i9*`?q2OxA zr^xWPZAx<9ja&+<)KnI@jJTqd$ihe}K_@$XzCdVc4Lf3wfQ=jbs^k2pbRkIUHJ+l& zY)`3DWX_oL%r@K4t#e%dw520@(h?K7UaTjRsm4VWOzs83l_zy>AQqHQ)Mr+qfa;Z^ zoVJ=Oe7Ml#1t2LuO!LR*rYRDy7xI2uaNx^w@VH{T4m)rrGYVoND5_ao@spG-uuAp@ z-US4LoxtM?)p8OB%5kt0WnKhyRjI2$xatWD#`REW&H0ZhSo}_e;NX90Wg}e~%kqH? z3!FY2Wj7rYFc zypEyx{{VzFzdCmZsg{#=b)iUHe~zfKgw$0Pxd?t&I4&vv9#Bb9<2z0dry3>)NgIr^ zyXE}Z36dk22%vAx7A;TYujxE`WN9_FY8AQ5VYNEMw-A(hgnGt8H(;NU2j!1y-egm`c-*Yz9PCw23yBuS&)E!O4QO6hSEJ{YDfuhkVXnqj>7{~$-23= z1*+1TKTi68a9waZJyMxeiBp`4NRYW`lM%UyL0pB$aU&(BT6YS`Bh26vjd~~a&Nhs5 zE4rV+57lqs3uT_A3Ob1FTC{qtJ^}NZj~QVJU#lxhN$2Ib0!P$qwaGUdf$X#-qS6&f zw{AzK-1VBuo(V!!84Aa@3Q^DeDc1uQL!UF{Sd4wVp2)@1`=+~cJj7Y@REUqDx|rz! zCARwoE8LQG(c@&~Oh=e@JJ+(&idVev!m{^;c1_LH&YWIN(WT2}nD8eliSinWEplN< zS{!~F)>4Al8E9@P1tji1`pJtNh$qJ+J4trkMeY<_*14}>XaH@nKVNcsl~MZnXfb_w zg_W|cNSdivJccB(N|L9Q8J8b%z}v(Pg=kLZ{KnLzuLB&U>zB)**yIkqhZ}V27F5ET z-&YFRczfuDr`IdOeG>GJmD+TATeGCcFRD5Tz-^=EB#nu0Dpyq@7Y21?DwPt)w1i_fKE>n&uwh*@x@&dzaa4l-{HYq9h z$9;7W&3=~+!eBupBNtKZs^?y98pW|lt-_fd=z%G!*JhL=Q-ma!P^Aseg*x6ug(C?Y zf&s~1ubIAM3qp}*p-3kW!IxO9=+p;jRC)t-S}je9%}IrFq3QBnZAs=b90?7Qw0wcc z$7G#kz85u|3LKkBkiNiQMr~gST?w$MQz|2;>{aV^M%L{2>p?TBE~)&Nf|lyGp?E}u+ae5y?=_Sh|gDTjkp%INi*^WOg#+!G{ zWl6~%Tgf00Q|Uq46Of&0OXD6I+mVkhl83Ma3cdOK(6RVNb6=^^fC0MPk~?-${<&7{ zD+-HR>HKNXZEK#S%k5k67(a6PFd_j3FfedVdPi zQm#QMBN#g5vLSSGlHR+oQo^1bs2F7%fS-Iw^)BYO`blhD((RE@x970bNpNZTYArQD zBq@mnqDmCCZ0~?_P)d6qs}4;x=W|QUd{!~4NTK_;UnCvrcUmorj{J+~+Hq4?1WA(f z%J`JFpg>9+E+b=j$N=F-`y)8cw7wwV-Pb*h;gOS}p-w6GTUYJlA z)Y*--;!=`Spq%XN5`p-JK-_gup22g1JM8U>n#5G2S$2GCo7E_^=}p7pIVgkzokM@J zR_4;7kTcHQ-~o}H3p9`7_gYxc2Y}!CTP_^?ZBB8I ze2x-*hOfcEGQ1nuD!fO;{>>Qyw`e)g{{Rvwre4*#SB+PEdQ)kI7BU=4Ta2=`Z*}yf z4>j*8NI-Lqsm=!_N3NBP$h|~cR}B-L3#n%YDwMS+xkVs_j%* zOx4@)+IghaR;0MZhaV$rSwbBuND3=olyEYldCY8wFllJqEsWm{bqS^fYM_1p0K!Gn zNejCAIZLk3s8s8984k;*guhlYAD9*DERg9bT8YZGs05wGL<|J$obgW($(m4Pe#4Jt zq2c(DLl%}cuazIJcwFd3DwA>4E-H(5wa*S1REm8bxTch}w9wp=;;GGHvErkWK(3_0$jEH>~83uz@Ao(f(vk`uWZ z2eL3p&NZ8wbh}e_T6hf-H$%m$Gvd;tTj{4!E*RD59}`Kc6`OP6CIH-eQdCgHX23g{ zEhlPl2N(yCtmqATg_K+4@>!Mv-%S_sxMn=SWNKA(_IIUClAxuMqCS1~0;CGH7Uzum{T9*b z#kp-bq_b~Oz5;oil{nk)84j%pN)yU}ONl^8($B+S31nw7c16p=ESX1`t9q*KHUzawZVS#h+7w1S&6`vTRg|S$lgLs5_Qrve56#`p zS{VK%CMXPJ_FlCiKThhLyYB6_tLnGu@|>M9#l{ah+s+f^t-`zokm7=lagsU4bEz?! zDYU73%&syXt4o8ZH#b)$%9u#lN0bKTC=J;-2e*AhwBHIRg_{br{VHRW=Nf4$a0IfsK_md7!b#5n zf-%VNqN8S00}F=6iqFd-j@72Z5kc^4)LM+zAVsmOSq#~({+H%;)9c)$;CY`$7nGa0407LoxAP5~u2$tT-s z`D%|S5n!Udc0p?12Zn00C{koT*mi0`EHoBV=PMZ40sWv)zA`dLZ6O&u1lP5dAnEsq z3*)HrV)>TzsyrwVT!WcR`Fo_G5Te*81oQZh8CSli97X1xvZhJ2Hrg#2EpG_dw_mQB zZHGGahaO#_LurUmr@n?((+g25LIW)q9V3#g@&O!>K-DhCixig*T&-?Y`HT&HQvzr4 z72$G;;qRri=I!d#=@(pCY>6+)hNy;P&M8VsjG##ck1TRX$m9TXr;2k$plnsoj5eMA zpsStt)!Uz_uhOcO_n^$11%k@tMvt-boZzkH4hbqCp1>2p8Pwr-l58i;o%vt~@;akM zKf|X|Ztj}F>SYexsz|58WlB`oD$I#7%F>m5I(T(XZaYHIf}h2Mfu_uoIVfJ}{{RY+ z*lsd7Z0)b89c$c;kmg-#nrjM?Y{Xp(lLIWpOr-=$cWTskI6?e*QO?ANB|XX9GnsXBZTk{v)_$I*t$5p zO@sjcsm{W@2TwYI0<8w50fh!>-kQ29_b#_K;@gOCQ zvun>;gC1PNTdA~xH*Ze*QPnB2Y6z>lZbD#SQ=P0Q%W-+azVXJ3o3ns>@Hp?R*t};d zKttmf?6g1VcyaF>n|qY$(q5-@&%)*Q{Zf?#Nut)_CYe4!eR4w~E(I4_3rbw!U~fU; zN%bUUARUZ(ACTL4rJIwF4l%ghX~(aADg{E|`wOSFXmjJd-sb8uVNoR#rvXtJs8lN#D>94o>k{4a*zNbNG|?NC>M2oiTX`4& zgPm8ZlNRb~hq(fi93aH=TvBj+!mzxN?oc@&#A;&D=dwdqxoQ*Ark;`U(UPx9UTr>~ zpuhzq=rO5{lPkC2i>oy5rCF7ZmR*hqn|cc3HiczQJj;X2!T{u{JG1f_$;W+h{w0X$ zXBjd706*n=H-hI3%y(hU$QAJ);YQ{E049CXg#h#ymJyEaqLz2&EZwHDY2 zB#=l-PZ_~E1nWosu@gYl(ob4hNBUWWw7LW*nb1u58Wl| z*N*u&RFO-zV?9r&g#>xwI7(aXgtgcZG6qHm%RpiH8EF#EY@>63sKbGe8MHXF+u)k~ zKSt^M>8Qk}MW0HnG}`9Kmn0dAOGzWkeFdd9P#Y^DTT_v^6$K=mb^2UQHE_VUnGekn zE=s>ntF(B(Y(`zgn5$5BWVpq`R!Is|i$XTGqDOF1+W?GfsgEBStPRs^my;tWS#WY8 zbYH|YZl9qERGG6abpx>sq$TvFD#MZ>lRnOx*NF#}GM6p3%?3lL zefAcFB|d9uQ3Q{ENAK4qa4`2(&{cR z1?dWCy7F+AQiUXXPne{g#1ssAff*X+JT5oBb39}2jh9K{WszZsq~=Y}=&84iNwIo8 zaf?1FjW(w2WJ_Gx5R#J(g_4$#lwh`(PST>b&fmhMgsXw*Fwf^RRZ(7dCOC=OZo;W@ zZz=Gq>X^&xRK=CJ>(4l)t<^6(iq)K`oSc*2I++$JN-13fgPF)tH{1?7rGd04=Woka zaG+5KrM+H})3*a=GG<2eJivzzdc8&J#lIOW{CjnXuY@!exHjx2kWn4EB}+bg%%Fzbe2+8B8x~cyD%Du< zz9$`Ae?J9(iDp5T(W3QV%D-{N^&Iena%C+|C$f;@0bU2~cK-k^9=X~{5<6!IVRR)KwWW`*`;K_6yCq6Zw2Aw&B2rAT#27z2}#ao7*yW)41fBxRl; z;9q?OZSYh(BM&3jg&B>z>`6PF$+Le&UoAeL)NV@jIt9N0>x$s0FUpGwGXcdopbD^& z^1vjVfB+{r){T?0t8!5ukI@+R?bS7&tjtBD5(PQw%ciD#EzOv&64Pubg&|>TD&?}i z8c;Ym)P}(^6s=!{3gri-RtLqZBhaZ8)Cmw0>rJ8MvK7jnbYU+zrH$C<%TCnk-;d`s zX*;MhGstlTyDO)1Soi%#GU8j-%v(y3pH}tAWfGk~*(=;qfKGC(EnfZfRCyTjk5jcd zSm<8!w!uZMp9|GIs%78Q8f7LstK7PEB5JU6-_4S;7UI5m$G$kzNt|A3t^5?D$72U5 z*==+R!c{ZNi54|Rn4)mgX$oaZ_dffN)RUa(aWn5_acCls35MZ;Y*XgB4%MQ!P^+|( z!mDx}bK&3*cF^cKDjmG0a0l%a`;k&Pw(_fKj5?Z|y1n8i^PpQUw`f{asTF5hQ(~)G zt}_~+72F&vX$9A@-)Knr6%9@-XUO0N>ba+mAW15zPoQ7@V15lltFmZwst{TcgvvBW z*`%tS)0<|gG_y*zDG}kX0hLW< z9%J8_P{|yACqFQdG;@SeH`FiWvRLV)ciul$#^|-HR{b2uwc$5ciWyvH>K6PTJ}hOa zf6^L3XDBNe2{=4_zFSycIf0K4l=p@^u?O@E)BGX{n}{oQUhhkpJuu%op!052mW8ls zkHdB&(g*~gZBWify2!>dGpnEDxQ_(m$R2BoKdRB0uf}ev2P(W+RIybY)@s@cfrC!KIUGn=8H>U}ITuqkgZ z$#8&IpF*+knqMQN@YcP~-K2{AkY&dz0WIzg+ z)|3KL9xkgsN|TbLp(LmC*Eb>5(@3ujm61(yKSAo ziK42P3DGIYZRxX2C@j)6L zI;BU0LyYV<*DdD0Kh7?=q=cbM7$`=-6h_iHTC>5%p_?4paF~yz9%)^R;!MVrNLmlE z;HBL&nb%IVwOwLYRhzc%SThpSa3a&uA`xdGsrAVVC;LfDX--sdNeRgujGheEI0tS! zl5KSm`0Vovhym~e=$+=2blqqjQR>ZRs_dqnKV;J&wH@C*x7=+?TbNL3rG%uQ092v9 zMBohb-_#Mo;oekOEb|=UXWQnz2l{3o74cZ5o^sZ-I)OY9S9CY7oP`yc;)9|cKW=Ll z`*+i`r+JE*QKZxuTH&^^LfK(*5K_ul!jzU03C0wxWjevbJ}%~mx+b@Nrmx{c^IF-_ z!{!!EGhL_stt12g0PVT<-@PP#MDdGh^;)HDJ0kt4(-?yJcpI|cz;U&0NKf=st-l~) zMOzY*tZh!*$%X$~Vt(WO{M3`!b+8b>N`||EWORhP&USFu70)jmxljY51%@Rg;_*HvW z%K+d>k0YRe0=OW9?_;`KROmF@s-rC4l$Tr*Nm^?*O*_{eN>=4KwvytDpyfo5Z16Y( zSk5HbJfnm|U=hOY@P$pXdMOI)v2Xd6%T*I2W)(o6DS)R#D#>vnZDW4b4^A>YI?X$s z){_Zo4FrXL?08ni)nQDvnU76&mWG|C&7?tER>WlGO*tJ~I7+=L+%ufy`;9m|?5dYl z+NIJw7e(lO(DZs8bIYwyZRY588iNWkVzNjJS=h?9xZ7k5sbrItjAw)6sSo!!2vepe z>W`9%y*TLGRJahSG@G_5fXb4$-DTxExhFoOwZ(g@u*V-#b$pTmxC*G^bA=L&Q|L6M zQr?kOQyZHYW#*dMu@Cmaxadk)&^;qeG@;?rKBxm=tHa-}XV*r8`vJQG{DMP6g}{{Y(-m3L;x zstN^6&3GrVX+S4$WQ76_Hz8SDavah^0e$aPr?PsDHC1wqk%1TdYS64J78gsUKF46)MHV;Z`tB?__B zS+d!iZ$hn!5tf&kl#S`~)|0s^1mI*44xGdMqw;vq$&9=v{tkN3i0L> z$>fem$N0*K?S)io?!L$0N@)vm^`$NprwIefZ3!wE zMiK!WDD$J<*0=_=RRx^QWu`|vR-?6a3bI%HCG`$9Rk$l|nyD%zDG^q%8zXLa z;Ad0&1k?zv(9X<>q=V5lC&E?uW-}bOAA70ayDn@`Yy~K!08V%szy6g!aEAW?szcGG zOXPSls8TI7)#^8ODm#x!ZX0bn@>yvLQcBdNt!E`EK+Y19Pt(4tb_)zNB-Ne4i($yrzGB6Y0V*FwgV%rt_45VIvVwZ zaN5)tTr!1fT&lHFN|+lYCO4Lr*+K!sXiB69Hj&Q6mN_7pY@N=I{!sH|K|i+(u;DL~B;1P;Fjn+JfUv zHs`1e5Qhf`*l~lAql8V7x7B36X(E&~@O{ud%TK8GMMb9{x9ZR$L21&2!E7xXRzjDR zf^)lI1m|%|K+Xm=p6K2k!qbiIEfjZF52xNP=~SvBs&)E%vuevzt}=oPjI{Dm%1R2- zN2_Q&k4lC!jB1w~2(a$z%=FUazwX+CohZxp=C?2gs z*49LXF}i3{ghjaF%4TFnSf<^NFn5NM(Tf}s=mEgukKW{~1O(s(A8hHJ84lZIgn`W6 zdj9~vu4*lM9kEcF)G8H1N0icOi4juYp!rEF<<}AEEu0kg0~~{+BV!9hjSC)Ey`{`3 zQFe6KsBgn&Rfk5XJ}GkCsZ(mSwpATb-b%1j=BR?T1dOFg&u&jAPnKhnJtnLv;Q5Sx zz3DVv7ZuIogxxE-s#8%SM3|C($D>78pB>f^8Cu;qODJ1}s{u{`JjI+TL}Mx}bHG}2 z<*}z!hJuV=J`t$)<-PXPPh3!`z@dqOZ8YKBv-fLQOQ+MgVB;fjJ-F0arOq++R?Nd2 z1cQZPd?EONhtn#wJ5v01iAI%0j~<&wpEf6!xv!R)UX}c3JBT{Bh{T&{C3$$ zPUBsaU&sFdh%S-bj@4+E{{T(xtBU!mFg`lx5%BaJrzu!vu$Rw3?k=@i0-D>3gHUV znsVf1u-j?nRh9U0xff|MUSj5i>uF@jdN~ViY!qZDda;s{f;i`m8r*oo$#zVn(qebR z-PX1jIq7jWAxG~N_)?VSH*M~6tYGoS*H(rBvWuMOB0Y`aR`cpjrtQH^xZ|d##FtRo ze9Q%}2~jyn;GQ|gax;xpE87tox~W9RNC^ooOTp(^D{n}vNQCUkl3MVuEP{AFwOG&B>n^9r8v4i0Hm+UL8fP-xc}Qy5zx7 zsLLbGbwg;{I7(8K;3WWX5;z~8y9nZJEev3wyrUx`OsNdA8zn~`p5v~SfD)p6q@4cz z>f|yobSf&XJHjo;bxKVdjO0g|LTUlV(>)I%O(_F!J2sUPuHKQ~RIxn521rmK@sY{atTO^h1!T(!X3pxY6)Uc`+;piG zn6;~>ERYM&DuB{Mq;@M)Y6)>^?Yqkh9N}YH4wai&zmgNlc^ew}qyGShuMzz+vTm6V zCb3Ya!mF?PWI2nH(pq%j7mH676$5}5w5#Xrb;x+ngvXQr0IJ9P;BGsG+xQ=g%K#WT zKXji-=SlsKf2y5$h4AN4wpCZXdR11ZyxX2^x%Sn4hpG_@K?-$n9YIo&xbx%>Njcb4 zjk*s9#~%elGq0uo=VD^rB}jsQpr8N>0+_h<1`-Ur8PTfPb5Ou`|rzh3vy)$vQ_pNQ6K zJwm>bc-AG;>a@zMF11OgMwV3cCQ#rBQ-LQbQnS2{{E?0|&|>&-@ceeh4(D_6T(5}u zneiN_zP4$h@I#CKpH#c5QR@}C^%*ndrZqipsR>bNHrQziaTy!1l#g0?IV6BjBs2z! z3p|o}QC0McvnpB|q`MlnR^nPnVbI#aQNluk@r<9YrG3)?N{3Y`GbptQ5GoN~gE}&c zZ$^;WZN`*4rAa)4`RZbdl~*Yl;OQn^n~--Rt2bGDvvksuSbr-<|^c;{|-IPH*qwCw`-RLQEXsIzVOE57cF^_om} z;x$TAgRfN^R`!@+fHIGDvm^oJge2kU!9((1gzxE` zQKgDlejtXVmy#0p&rhM$tfP8J-QRjulk?Z9#7m*r;mX7Ea`2g~P}JeOiR;sjIV!pM(3fIQxZ=mQqo$Bs zh49FJMCBnRNLtsGAz-c2LX?uCLPmCgPTU{ixp^6Jmt-3wgYE9Id~?IGuqA78+69X> z#r*f(SMHZcx@;Qbb$Im3d+Cz`OfQD7Fr~EQc`PZl9e{=4p=6~=BlQ^vXpjo!lhZJ* z*%Y$7vfZoJXQfWK?Ov5}vl#>_MP8WhM41}dM>oRW7Vq> zsL~X%P`7UCA}ciMO6SXYA(ey$rwIgrg=ZY75(Q2K{{V!WLw)kfbg+`~wY@#a> z)HaE=hXMf|&cwK)wfE0B&&=rH9eb;Fil9>V?%N)c+m1gc`O6|Yz$k$UPobmi07^mu z{d1}5nCt~8Ym9PtN-JGScH*H(LM>U1!B7cT+Oty$81@7-RJ?z5bM(>}?gsC57tGKQ z_P5mv-3}v&k4U4i(Wr<) zb2qm0WjRx9;DC1p6(v5Tl@0=Uq)Pnrkae6g=KDht!oR z_kF!7C`lZwiIRrJh|UabHdU02)9~ zIK=-%A0jK;!CZ~r7z*pklONx8Qw~X2_D^%^Q5ttXeGTG&sds2Ub`){A z4pKqaseAoM|}_{ zb2vi1jdtZjD&8*U+jHkrrarY(Qzgi%Fy7ekNcZFBI}wqh21x13RV2!2kH>e$(?Y~~0kwcP+t@w25S4{dvadncPXus4qsV#g=DD$K;X|on^6(P9I zfQ3eEoRosT0=YX?t>!}Ks;|$R58ci|P zAu1yPywKwW<10=-Ene4xXsGH0DGiMes$Em*w7LxDYSg})R#y6IQqbgd2|i1S-i@kO z_RtjADpt{uoFpDji-Qfa$|RH!JB68<;t!367+f{>Rv*KK$#(c|={vNGJ_~oku1c%Z zsE{i&Q4M)1N?mnIOKMV^B`IIaBqS(g;ibb5d%Tmd{(VtV<~y zh7qqTy8gfDmgT4LffVN&k%khH5UnXG8Eq#DX&_{0fxPk1PpX`luQjsHzfZ26$wXw!E@`&`c z$cJZ0nRHYZs0fay)? z4x27pPI(cSioi>*ET?fUt<@IN+i1#^NWw`-J2buTI3^l{}!JafBq~t3mygHHFe2S7boQw+2QwLf*L5Z~L(q9Rd23 z>aDd72x6g6OaOmCfWK(vHCYR1dYAwp4Wl5dZy;bND^~KEhQ~CK zHPW5Ru$C3EOKPzWgDIxvOGH5HK6F*O(+wo@>fLk_qLG40B}Gdo0Ao}JA1>L~WuYUQ z$tlN$II?MU=lrYMwy2a^3yTj^#YISr6ojayg{?~|!P}K=JmqI2BUVkQGs|ZE)?`-a znO(<4(*ElwPOEf@5al;gz2iqyGaqJ)8P6+wZU-aoc}i_3D?m_4Q3~2SjZqFf+_YEt z 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 M>SdHWkF9_I*->xl&j0`b literal 0 HcmV?d00001 From 560350b4de33f74e7544f718bef74ee613896ad9 Mon Sep 17 00:00:00 2001 From: Ihor Sychevskyi <26163841+Arhell@users.noreply.github.com> Date: Wed, 19 Feb 2020 19:02:26 +0200 Subject: [PATCH 053/111] Fix Invalid link in readme section (#19178) --- README-ru.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README-ru.md b/README-ru.md index aab0adcbd1..5b110b903d 100644 --- a/README-ru.md +++ b/README-ru.md @@ -34,7 +34,7 @@ > Если вы используете Windows, вам необходимо установить дополнительные инструменты через [Chocolatey](https://chocolatey.org). `choco install make` -> Если вы хотите запустить сайт локально без Docker, обратитесь к разделу [Запуск сайта с помощью Hugo](#running-the-site-locally-using-hugo) ниже на этой странице. +> Если вы хотите запустить сайт локально без Docker, обратитесь к разделу [Запуск сайта с помощью Hugo](#запуск-сайта-с-помощью-hugo) ниже на этой странице. Когда Docker [установлен и запущен](https://www.docker.com/get-started), соберите локально Docker-образ `kubernetes-hugo`, выполнив команду в консоли: From f16c41b5ac1cc3424ec9347610ca8ecdf3550cf5 Mon Sep 17 00:00:00 2001 From: Fabian Ruff Date: Wed, 19 Feb 2020 21:13:33 +0100 Subject: [PATCH 054/111] Fix inital alpha version of ValidateProxyRedirects (#19192) See: https://github.com/kubernetes/kubernetes/pull/88260 --- .../reference/command-line-tools-reference/feature-gates.md | 2 +- .../reference/command-line-tools-reference/feature-gates.md | 2 +- 2 files changed, 2 insertions(+), 2 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 b02b3e48bd..b0b24ba517 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 @@ -146,7 +146,7 @@ different Kubernetes components. | `TokenRequestProjection` | `true` | Beta | 1.12 | | | `TTLAfterFinished` | `false` | Alpha | 1.12 | | | `TopologyManager` | `false` | Alpha | 1.16 | | -| `ValidateProxyRedirects` | `false` | Alpha | 1.10 | 1.13 | +| `ValidateProxyRedirects` | `false` | Alpha | 1.12 | 1.13 | | `ValidateProxyRedirects` | `true` | Beta | 1.14 | | | `VolumePVCDataSource` | `false` | Alpha | 1.15 | 1.15 | | `VolumePVCDataSource` | `true` | Beta | 1.16 | | diff --git a/content/ja/docs/reference/command-line-tools-reference/feature-gates.md b/content/ja/docs/reference/command-line-tools-reference/feature-gates.md index 92fb9868df..b20bbcfd23 100644 --- a/content/ja/docs/reference/command-line-tools-reference/feature-gates.md +++ b/content/ja/docs/reference/command-line-tools-reference/feature-gates.md @@ -139,7 +139,7 @@ content_template: templates/concept | `TokenRequestProjection` | `true` | Beta | 1.12 | | | `TTLAfterFinished` | `false` | Alpha | 1.12 | | | `TopologyManager` | `false` | Alpha | 1.16 | | -| `ValidateProxyRedirects` | `false` | Alpha | 1.10 | 1.13 | +| `ValidateProxyRedirects` | `false` | Alpha | 1.12 | 1.13 | | `ValidateProxyRedirects` | `true` | Beta | 1.14 | | | `VolumePVCDataSource` | `false` | Alpha | 1.15 | 1.15 | | `VolumePVCDataSource` | `true` | Beta | 1.16 | | From fefda3e4ea11ed54f0c73e9db3af6a578fe67531 Mon Sep 17 00:00:00 2001 From: Jamie Luckett Date: Wed, 19 Feb 2020 20:38:48 +0000 Subject: [PATCH 055/111] Add missing space in documentation line (#19013) --- content/en/docs/reference/kubectl/docker-cli-to-kubectl.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/reference/kubectl/docker-cli-to-kubectl.md b/content/en/docs/reference/kubectl/docker-cli-to-kubectl.md index b86ee27042..7def04e04c 100644 --- a/content/en/docs/reference/kubectl/docker-cli-to-kubectl.md +++ b/content/en/docs/reference/kubectl/docker-cli-to-kubectl.md @@ -281,7 +281,7 @@ kubectl get po -l run=nginx-app ``` {{< note >}} -When you use kubectl, you don't delete the pod directly.You have to first delete the Deployment that owns the pod. If you delete the pod directly, the Deployment recreates the pod. +When you use kubectl, you don't delete the pod directly. You have to first delete the Deployment that owns the pod. If you delete the pod directly, the Deployment recreates the pod. {{< /note >}} ## docker login From 6a3c364706c49b1603f6f1ae56d8d2dae5af5921 Mon Sep 17 00:00:00 2001 From: Tim Bannister Date: Wed, 19 Feb 2020 20:49:45 +0000 Subject: [PATCH 056/111] =?UTF-8?q?Reword=20=E2=80=9CCreating=20a=20single?= =?UTF-8?q?=20control-plane=20cluster=20with=20kubeadm=E2=80=9D=20(#18939)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Consolidate words of caution about Pod network * Tweak wording - use tooltips - fix a TODO hyperlink - adopt style guidelines * Revise prerequisites for kubeadm * Rework page structure - Replace some headings with anchor elements (preserving inbound links) - Use a "discussion" section for the discussion part of the page. - Make Feedback be a part of the What's Next section - Skip mentioning Docker in a logging context; provide generic signposting instead. - Update overview - Document limitations and fix link to HA topology - Fixes for styling * Redo network plugin info * Use glossary tooltips to introduce terms --- .../compute-storage-net/network-plugins.md | 2 +- .../tools/kubeadm/create-cluster-kubeadm.md | 290 ++++++++++-------- 2 files changed, 159 insertions(+), 133 deletions(-) diff --git a/content/en/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins.md b/content/en/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins.md index cb9b6d83a9..3cb5f3ffa8 100644 --- a/content/en/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins.md +++ b/content/en/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins.md @@ -12,7 +12,7 @@ weight: 10 {{% capture overview %}} {{< feature-state state="alpha" >}} -{{< warning >}}Alpha features change rapidly. {{< /warning >}} +{{< caution >}}Alpha features can change rapidly. {{< /caution >}} Network plugins in Kubernetes come in a few flavors: diff --git a/content/en/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm.md b/content/en/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm.md index bfb26fa1ca..2c978b0653 100644 --- a/content/en/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm.md +++ b/content/en/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm.md @@ -8,63 +8,50 @@ weight: 30 {{% capture overview %}} -**kubeadm** helps you bootstrap a minimum viable Kubernetes cluster that conforms to best practices. With kubeadm, your cluster should pass [Kubernetes Conformance tests](https://kubernetes.io/blog/2017/10/software-conformance-certification). Kubeadm also supports other cluster -lifecycle functions, such as upgrades, downgrade, and managing [bootstrap tokens](/docs/reference/access-authn-authz/bootstrap-tokens/). +The `kubeadm` tool helps you bootstrap a minimum viable Kubernetes cluster that conforms to best practices. In fact, you can use `kubeadm` to set up a cluster that will pass the [Kubernetes Conformance tests](https://kubernetes.io/blog/2017/10/software-conformance-certification). +`kubeadm` also supports other cluster +lifecycle functions, such as [bootstrap tokens](/docs/reference/access-authn-authz/bootstrap-tokens/) and cluster upgrades. -Because you can install kubeadm on various types of machine (e.g. laptop, server, -Raspberry Pi, etc.), it's well suited for integration with provisioning systems -such as Terraform or Ansible. +The `kubeadm` tool is good if you need: -kubeadm's simplicity means it can serve a wide range of use cases: +- A simple way for you to try out Kubernetes, possibly for the first time. +- A way for existing users to automate setting up a cluster and test their application. +- A building block in other ecosystem and/or installer tools with a larger + scope. -- New users can start with kubeadm to try Kubernetes out for the first time. -- Users familiar with Kubernetes can spin up clusters with kubeadm and test their applications. -- Larger projects can include kubeadm as a building block in a more complex system that can also include other installer tools. - -kubeadm is designed to be a simple way for new users to start trying -Kubernetes out, possibly for the first time, a way for existing users to -test their application on and stitch together a cluster easily, and also to be -a building block in other ecosystem and/or installer tool with a larger -scope. - -You can install _kubeadm_ very easily on operating systems that support -installing deb or rpm packages. The responsible SIG for kubeadm, -[SIG Cluster Lifecycle](https://github.com/kubernetes/community/tree/master/sig-cluster-lifecycle), provides these packages pre-built for you, -but you may also build them from source for other OSes. - - -### kubeadm maturity - -kubeadm's overall feature state is **GA**. Some sub-features, like the configuration -file API are still under active development. The implementation of creating the cluster -may change slightly as the tool evolves, but the overall implementation should be pretty stable. -Any commands under `kubeadm alpha` are by definition, supported on an alpha level. - - -### Support timeframes - -Kubernetes releases are generally supported for nine months, and during that -period a patch release may be issued from the release branch if a severe bug or -security issue is found. Here are the latest Kubernetes releases and the support -timeframe; which also applies to `kubeadm`. - -| Kubernetes version | Release month | End-of-life-month | -|--------------------|----------------|-------------------| -| v1.13.x | December 2018 | September 2019   | -| v1.14.x | March 2019 | December 2019   | -| v1.15.x | June 2019 | March 2020   | -| v1.16.x | September 2019 | June 2020   | +You can install and use `kubeadm` on various machines: your laptop, a set +of cloud servers, a Raspberry Pi, and more. Whether you're deploying into the +cloud or on-premises, you can integrate `kubeadm` into provisioning systems such +as Ansible or Terraform. {{% /capture %}} {{% capture prerequisites %}} -- One or more machines running a deb/rpm-compatible OS, for example Ubuntu or CentOS -- 2 GB or more of RAM per machine. Any less leaves little room for your +To follow this guide, you need: + +- One or more machines running a deb/rpm-compatible Linux OS; for example: Ubuntu or CentOS. +- 2 GiB or more of RAM per machine--any less leaves little room for your apps. -- 2 CPUs or more on the control-plane node -- Full network connectivity among all machines in the cluster. A public or - private network is fine. +- At least 2 CPUs on the machine that you use as a control-plane node. +- Full network connectivity among all machines in the cluster. You can use either a + public or a private network. + + +You also need to use a version of `kubeadm` that can deploy the version +of Kubernetes that you want to use in your new cluster. + +[Kubernetes' version and version skew support policy](https://kubernetes.io/docs/setup/release/version-skew-policy/#supported-versions) applies to `kubeadm` as well as to Kubernetes overall. +Check that policy to learn about what versions of Kubernetes and `kubeadm` +are supported. This page is written for Kubernetes {{< param "version" >}}. + +The `kubeadm` tool's overall feature state is General Availability (GA). Some sub-features are +still under active development. The implementation of creating the cluster may change +slightly as the tool evolves, but the overall implementation should be pretty stable. + +{{< note >}} +Any commands under `kubeadm alpha` are, by definition, supported on an alpha level. +{{< /note >}} {{% /capture %}} @@ -94,27 +81,29 @@ After you initialize your control-plane, the kubelet runs normally. ### Initializing your control-plane node The control-plane node is the machine where the control plane components run, including -etcd (the cluster database) and the API server (which the kubectl CLI +{{< glossary_tooltip term_id="etcd" >}} (the cluster database) and the +{{< glossary_tooltip text="API Server" term_id="kube-apiserver" >}} +(which the {{< glossary_tooltip text="kubectl" term_id="kubectl" >}} command line tool communicates with). -1. (Recommended) If you have plans to upgrade this single control-plane kubeadm cluster +1. (Recommended) If you have plans to upgrade this single control-plane `kubeadm` cluster to high availability you should specify the `--control-plane-endpoint` to set the shared endpoint for all control-plane nodes. Such an endpoint can be either a DNS name or an IP address of a load-balancer. 1. Choose a Pod network add-on, and verify whether it requires any arguments to -be passed to kubeadm initialization. Depending on which +be passed to `kubeadm init`. Depending on which third-party provider you choose, you might need to set the `--pod-network-cidr` to a provider-specific value. See [Installing a Pod network add-on](#pod-network). -1. (Optional) Since version 1.14, kubeadm will try to detect the container runtime on Linux +1. (Optional) Since version 1.14, `kubeadm` tries to detect the container runtime on Linux by using a list of well known domain socket paths. To use different container runtime or if there are more than one installed on the provisioned node, specify the `--cri-socket` argument to `kubeadm init`. See [Installing runtime](/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#installing-runtime). -1. (Optional) Unless otherwise specified, kubeadm uses the network interface associated +1. (Optional) Unless otherwise specified, `kubeadm` uses the network interface associated with the default gateway to set the advertise address for this particular control-plane node's API server. To use a different network interface, specify the `--apiserver-advertise-address=` argument to `kubeadm init`. To deploy an IPv6 Kubernetes cluster using IPv6 addressing, you must specify an IPv6 address, for example `--apiserver-advertise-address=fd00::101` 1. (Optional) Run `kubeadm config images pull` prior to `kubeadm init` to verify -connectivity to gcr.io registries. +connectivity to the gcr.io container image registry. To initialize the control-plane node run: @@ -258,26 +247,43 @@ created, and deleted with the `kubeadm token` command. See the ### Installing a Pod network add-on {#pod-network} {{< caution >}} -This section contains important information about installation and deployment order. Read it carefully before proceeding. +This section contains important information about networking setup and +deployment order. +Read all of this advice carefully before proceeding. + +**You must deploy a +{{< glossary_tooltip text="Container Network Interface" term_id="cni" >}} +(CNI) based Pod network add-on so that your Pods can communicate with each other. +Cluster DNS (CoreDNS) will not start up before a network is installed.** + +- Take care that your Pod network must not overlap with any of the host + networks: you are likely to see problems if there is any overlap. + (If you find a collision between your network plugin’s preferred Pod + network and some of your host networks, you should think of a suitable + CIDR block to use instead, then use that during `kubeadm init` with + `--pod-network-cidr` and as a replacement in your network plugin’s YAML). + +- By default, `kubeadm` sets up your cluster to use and enforce use of + [RBAC](/docs/reference/access-authn-authz/rbac/) (role based access + control). + Make sure that your Pod network plugin supports RBAC, and so do any manifests + that you use to deploy it. + +- If you want to use IPv6--either dual-stack, or single-stack IPv6 only + networking--for your cluster, make sure that your Pod network plugin + supports IPv6. + IPv6 support was added to CNI in [v0.6.0](https://github.com/containernetworking/cni/releases/tag/v0.6.0). + {{< /caution >}} -You must install a Pod network add-on so that your Pods can communicate with -each other. +Several external projects provide Kubernetes Pod networks using CNI, some of which also +support [Network Policy](/docs/concepts/services-networking/networkpolicies/). -**The network must be deployed before any applications. Also, CoreDNS will not start up before a network is installed. -kubeadm only supports Container Network Interface (CNI) based networks (and does not support kubenet).** +See the list of available +[networking and network policy add-ons](https://kubernetes.io/docs/concepts/cluster-administration/addons/#networking-and-network-policy). -Several projects provide Kubernetes Pod networks using CNI, some of which also -support [Network Policy](/docs/concepts/services-networking/networkpolicies/). See the [add-ons page](/docs/concepts/cluster-administration/addons/) for a complete list of available network add-ons. -- IPv6 support was added in [CNI v0.6.0](https://github.com/containernetworking/cni/releases/tag/v0.6.0). See each plugin's documentation to see if it supports IPv6. - -Note that kubeadm sets up a more secure cluster by default and enforces use of [RBAC](/docs/reference/access-authn-authz/rbac/). -Make sure that your network manifest supports RBAC. - -Also, beware, that your Pod network must not overlap with any of the host networks as this can cause issues. -If you find a collision between your network plugin’s preferred Pod network and some of your host networks, you should think of a suitable CIDR replacement and use that during `kubeadm init` with `--pod-network-cidr` and as a replacement in your network plugin’s YAML. - -You can install a Pod network add-on with the following command on the control-plane node or a node that has the kubeconfig credentials: +You can install a Pod network add-on with the following command on the +control-plane node or a node that has the kubeconfig credentials: ```bash kubectl apply -f @@ -291,7 +297,7 @@ Below you can find installation instructions for some popular Pod network plugin {{% tab name="Calico" %}} [Calico](https://docs.projectcalico.org/latest/introduction/) is a networking and network policy provider. Calico supports a flexible set of networking options so you can choose the most efficient option for your situation, including non-overlay and overlay networks, with or without BGP. Calico uses the same engine to enforce network policy for hosts, pods, and (if using Istio & Envoy) applications at the service mesh layer. Calico works on several architectures, including `amd64`, `arm64`, and `ppc64le`. -By default, Calico uses `192.168.0.0/16` as the Pod network CIDR, though this can be configured in the calico.yaml file. For Calico to work correctly, you need to pass this same CIDR to the kubeadm init command using the `--pod-network-cidr=192.168.0.0/16` flag or via the kubeadm configuration. +By default, Calico uses `192.168.0.0/16` as the Pod network CIDR, though this can be configured in the calico.yaml file. For Calico to work correctly, you need to pass this same CIDR to the `kubeadm init` command using the `--pod-network-cidr=192.168.0.0/16` flag or via kubeadm's configuration. ```shell kubectl apply -f https://docs.projectcalico.org/v3.11/manifests/calico.yaml @@ -340,13 +346,11 @@ For `flannel` to work correctly, you must pass `--pod-network-cidr=10.244.0.0/16 Set `/proc/sys/net/bridge/bridge-nf-call-iptables` to `1` by running `sysctl net.bridge.bridge-nf-call-iptables=1` to pass bridged IPv4 traffic to iptables' chains. This is a requirement for some CNI plugins to work, for more information -please see [here](/docs/concepts/cluster-administration/network-plugins/#network-plugin-requirements). +please see [Network Plugin Requirements](/docs/concepts/cluster-administration/network-plugins/#network-plugin-requirements). -Make sure that your firewall rules allow UDP ports 8285 and 8472 traffic for all hosts participating in the overlay network. -see [here -](https://coreos.com/flannel/docs/latest/troubleshooting.html#firewalls). +Make sure that your firewall rules allow UDP ports 8285 and 8472 traffic for all hosts participating in the overlay network. The [Firewall](https://coreos.com/flannel/docs/latest/troubleshooting.html#firewalls) section of Flannel's troubleshooting guide explains about this in more detail. -Note that `flannel` works on `amd64`, `arm`, `arm64`, `ppc64le` and `s390x` under Linux. +Flannel works on `amd64`, `arm`, `arm64`, `ppc64le` and `s390x` architectures under Linux. Windows (`amd64`) is claimed as supported in v0.11.0 but the usage is undocumented. ```shell @@ -360,23 +364,23 @@ For more information about `flannel`, see [the CoreOS flannel repository on GitH {{% tab name="Kube-router" %}} Set `/proc/sys/net/bridge/bridge-nf-call-iptables` to `1` by running `sysctl net.bridge.bridge-nf-call-iptables=1` to pass bridged IPv4 traffic to iptables' chains. This is a requirement for some CNI plugins to work, for more information -please see [here](/docs/concepts/cluster-administration/network-plugins/#network-plugin-requirements). +please see [Network Plugin Requirements](/docs/concepts/cluster-administration/network-plugins/#network-plugin-requirements). Kube-router relies on kube-controller-manager to allocate Pod CIDR for the nodes. Therefore, use `kubeadm init` with the `--pod-network-cidr` flag. Kube-router provides Pod networking, network policy, and high-performing IP Virtual Server(IPVS)/Linux Virtual Server(LVS) based service proxy. -For information on setting up Kubernetes cluster with Kube-router using kubeadm, please see official [setup guide](https://github.com/cloudnativelabs/kube-router/blob/master/docs/kubeadm.md). +For information on using the `kubeadm` tool to set up a Kubernetes cluster with Kube-router, please see the official [setup guide](https://github.com/cloudnativelabs/kube-router/blob/master/docs/kubeadm.md). {{% /tab %}} {{% tab name="Weave Net" %}} Set `/proc/sys/net/bridge/bridge-nf-call-iptables` to `1` by running `sysctl net.bridge.bridge-nf-call-iptables=1` to pass bridged IPv4 traffic to iptables' chains. This is a requirement for some CNI plugins to work, for more information -please see [here](/docs/concepts/cluster-administration/network-plugins/#network-plugin-requirements). +please see [Network Plugin Requirements](/docs/concepts/cluster-administration/network-plugins/#network-plugin-requirements). -The official Weave Net set-up guide is [here](https://www.weave.works/docs/net/latest/kube-addon/). +For more information on setting up your Kubernetes cluster with Weave Net, please see [Integrating Kubernetes via the Addon]((https://www.weave.works/docs/net/latest/kube-addon/). -Weave Net works on `amd64`, `arm`, `arm64` and `ppc64le` without any extra action required. +Weave Net works on `amd64`, `arm`, `arm64` and `ppc64le` platforms without any extra action required. Weave Net sets hairpin mode by default. This allows Pods to access themselves via their Service IP address if they don't know their PodIP. @@ -389,10 +393,12 @@ kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl versio Once a Pod network has been installed, you can confirm that it is working by -checking that the CoreDNS Pod is Running in the output of `kubectl get pods --all-namespaces`. +checking that the CoreDNS Pod is `Running` in the output of `kubectl get pods --all-namespaces`. And once the CoreDNS Pod is up and running, you can continue by joining your nodes. -If your network is not working or CoreDNS is not in the Running state, checkout our [troubleshooting docs](/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm/). +If your network is not working or CoreDNS is not in the `Running` state, check out the +[troubleshooting guide](/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm/) +for `kubeadm`. ### Control plane node isolation @@ -424,19 +430,19 @@ The nodes are where your workloads (containers and Pods, etc) run. To add new no * Become root (e.g. `sudo su -`) * Run the command that was output by `kubeadm init`. For example: -``` bash +```bash kubeadm join --token : --discovery-token-ca-cert-hash sha256: ``` If you do not have the token, you can get it by running the following command on the control-plane node: -``` bash +```bash kubeadm token list ``` The output is similar to this: -``` console +```console TOKEN TTL EXPIRES USAGES DESCRIPTION EXTRA GROUPS 8ewj1p.9r9hcjoqgajrj4gi 23h 2018-06-12T02:51:28Z authentication, The default bootstrap system: signing token generated by bootstrappers: @@ -447,26 +453,26 @@ TOKEN TTL EXPIRES USAGES DESCRIPTION By default, tokens expire after 24 hours. If you are joining a node to the cluster after the current token has expired, you can create a new token by running the following command on the control-plane node: -``` bash +```bash kubeadm token create ``` The output is similar to this: -``` console +```console 5didvk.d09sbcov8ph2amjw ``` If you don't have the value of `--discovery-token-ca-cert-hash`, you can get it by running the following command chain on the control-plane node: -``` bash +```bash openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | \ openssl dgst -sha256 -hex | sed 's/^.* //' ``` -The output is similar to this: +The output is similar to: -``` console +```console 8cb2de97839780a412b93877f8507ad6c94f73add17d5d7058e91741c9d5ec78 ``` @@ -498,7 +504,7 @@ In order to get a kubectl on some other computer (e.g. laptop) to talk to your cluster, you need to copy the administrator kubeconfig file from your control-plane node to your workstation like this: -``` bash +```bash scp root@:/etc/kubernetes/admin.conf . kubectl --kubeconfig ./admin.conf get nodes ``` @@ -529,11 +535,18 @@ kubectl --kubeconfig ./admin.conf proxy You can now access the API Server locally at `http://localhost:8001/api/v1` -## Tear down {#tear-down} +## Clean up {#tear-down} -To undo what kubeadm did, you should first [drain the -node](/docs/reference/generated/kubectl/kubectl-commands#drain) and make -sure that the node is empty before shutting it down. +If you used disposable servers for your cluster, for testing, you can +switch those off and do no further clean up. You can use +`kubectl config delete-cluster` to delete your local references to the +cluster. + +However, if you want to deprovision your cluster more cleanly, you should +first [drain the node](/docs/reference/generated/kubectl/kubectl-commands#drain) +and make sure that the node is empty, then deconfigure the node. + +### Remove the node Talking to the control-plane node with the appropriate credentials, run: @@ -542,7 +555,7 @@ kubectl drain --delete-local-data --force --ignore-daemonsets kubectl delete node ``` -Then, on the node being removed, reset all kubeadm installed state: +Then, on the node being removed, reset all `kubeadm` installed state: ```bash kubeadm reset @@ -563,47 +576,55 @@ ipvsadm -C If you wish to start over simply run `kubeadm init` or `kubeadm join` with the appropriate arguments. -More options and information about the -[`kubeadm reset command`](/docs/reference/setup-tools/kubeadm/kubeadm-reset/). +### Clean up the control plane -## Maintaining a cluster {#lifecycle} +You can use `kubeadm reset` on the control plane host to trigger a best-effort +clean up. -Instructions for maintaining kubeadm clusters (e.g. upgrades,downgrades, etc.) can be found [here.](/docs/tasks/administer-cluster/kubeadm) +See the [`kubeadm reset`](/docs/reference/setup-tools/kubeadm/kubeadm-reset/) +reference documentation for more information about this subcommand and its +options. -## Explore other add-ons {#other-addons} +{{% /capture %}} -See the [list of add-ons](/docs/concepts/cluster-administration/addons/) to explore other add-ons, -including tools for logging, monitoring, network policy, visualization & -control of your Kubernetes cluster. +{{% capture discussion %}} ## What's next {#whats-next} * Verify that your cluster is running properly with [Sonobuoy](https://github.com/heptio/sonobuoy) -* Learn about kubeadm's advanced usage in the [kubeadm reference documentation](/docs/reference/setup-tools/kubeadm/kubeadm) +* See [Upgrading kubeadm clusters](/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade/) + for details about upgrading your cluster using `kubeadm`. +* Learn about advanced `kubeadm` usage in the [kubeadm reference documentation](/docs/reference/setup-tools/kubeadm/kubeadm) * Learn more about Kubernetes [concepts](/docs/concepts/) and [`kubectl`](/docs/user-guide/kubectl-overview/). -* Configure log rotation. You can use **logrotate** for that. When using Docker, you can specify log rotation options for Docker daemon, for example `--log-driver=json-file --log-opt=max-size=10m --log-opt=max-file=5`. See [Configure and troubleshoot the Docker daemon](https://docs.docker.com/engine/admin/) for more details. * See the [Cluster Networking](/docs/concepts/cluster-administration/networking/) page for a bigger list of Pod network add-ons. +* See the [list of add-ons](/docs/concepts/cluster-administration/addons/) to + explore other add-ons, including tools for logging, monitoring, network policy, visualization & + control of your Kubernetes cluster. +* Configure how your cluster handles logs for cluster events and from + applications running in Pods. + See [Logging Architecture](/docs/concepts/cluster-administration/logging/) for + an overview of what is involved. -## Feedback {#feedback} +### Feedback {#feedback} -* For bugs, visit [kubeadm GitHub issue tracker](https://github.com/kubernetes/kubeadm/issues) -* For support, visit kubeadm Slack Channel: - [#kubeadm](https://kubernetes.slack.com/messages/kubeadm/) -* General SIG Cluster Lifecycle Development Slack Channel: +* For bugs, visit the [kubeadm GitHub issue tracker](https://github.com/kubernetes/kubeadm/issues) +* For support, visit the + [#kubeadm](https://kubernetes.slack.com/messages/kubeadm/) Slack channel +* General SIG Cluster Lifecycle development Slack channel: [#sig-cluster-lifecycle](https://kubernetes.slack.com/messages/sig-cluster-lifecycle/) -* SIG Cluster Lifecycle [SIG information](#TODO) -* SIG Cluster Lifecycle Mailing List: +* SIG Cluster Lifecycle [SIG information](https://github.com/kubernetes/community/tree/master/sig-cluster-lifecycle#readme) +* SIG Cluster Lifecycle mailing list: [kubernetes-sig-cluster-lifecycle](https://groups.google.com/forum/#!forum/kubernetes-sig-cluster-lifecycle) ## Version skew policy {#version-skew-policy} -The kubeadm CLI tool of version vX.Y may deploy clusters with a control plane of version vX.Y or vX.(Y-1). -kubeadm CLI vX.Y can also upgrade an existing kubeadm-created cluster of version vX.(Y-1). +The `kubeadm` tool of version vX.Y may deploy clusters with a control plane of version vX.Y or vX.(Y-1). +`kubeadm` vX.Y can also upgrade an existing kubeadm-created cluster of version vX.(Y-1). Due to that we can't see into the future, kubeadm CLI vX.Y may or may not be able to deploy vX.(Y+1) clusters. -Example: kubeadm v1.8 can deploy both v1.7 and v1.8 clusters and upgrade v1.7 kubeadm-created clusters to +Example: `kubeadm` v1.8 can deploy both v1.7 and v1.8 clusters and upgrade v1.7 kubeadm-created clusters to v1.8. These resources provide more information on supported version skew between kubelets and the control plane, and other Kubernetes components: @@ -611,7 +632,24 @@ These resources provide more information on supported version skew between kubel * Kubernetes [version and version-skew policy](/docs/setup/release/version-skew-policy/) * Kubeadm-specific [installation guide](/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#installing-kubeadm-kubelet-and-kubectl) -## kubeadm works on multiple platforms {#multi-platform} +## Limitations {#limitations} + +### Cluster resilience {#resilience} + +The cluster created here has a single control-plane node, with a single etcd database +running on it. This means that if the control-plane node fails, your cluster may lose +data and may need to be recreated from scratch. + +Workarounds: + +* Regularly [back up etcd](https://coreos.com/etcd/docs/latest/admin_guide.html). The + etcd data directory configured by kubeadm is at `/var/lib/etcd` on the control-plane node. + +* Use multiple control-plane nodes. You can read + [Options for Highly Available topology](/docs/setup/production-environment/tools/kubeadm/ha-topology/) to pick a cluster + topology that provides higher availabilty. + +### Platform compatibility {#multi-platform} kubeadm deb/rpm packages and binaries are built for amd64, arm (32-bit), arm64, ppc64le, and s390x following the [multi-platform @@ -623,20 +661,8 @@ Only some of the network providers offer solutions for all platforms. Please con network providers above or the documentation from each provider to figure out whether the provider supports your chosen platform. -## Limitations {#limitations} - -The cluster created here has a single control-plane node, with a single etcd database -running on it. This means that if the control-plane node fails, your cluster may lose -data and may need to be recreated from scratch. - -Workarounds: - -* Regularly [back up etcd](https://coreos.com/etcd/docs/latest/admin_guide.html). The - etcd data directory configured by kubeadm is at `/var/lib/etcd` on the control-plane node. - -* Use multiple control-plane nodes by completing the - [HA setup](/docs/setup/independent/ha-topology) instead. - ## Troubleshooting {#troubleshooting} If you are running into difficulties with kubeadm, please consult our [troubleshooting docs](/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm/). + +{{% /capture %}} From e433c954d05082188d84149ff92cadcda097c01a Mon Sep 17 00:00:00 2001 From: Jacky Wu Date: Thu, 20 Feb 2020 05:03:46 +0800 Subject: [PATCH 057/111] Kill all federation v1 related tasks pages. (#17949) --- content/en/docs/tasks/federation/_index.md | 5 - .../administer-federation/_index.md | 5 - .../administer-federation/cluster.md | 119 ---- .../administer-federation/configmap.md | 89 --- .../administer-federation/daemonset.md | 83 --- .../administer-federation/deployment.md | 111 ---- .../administer-federation/events.md | 50 -- .../federation/administer-federation/hpa.md | 184 ------ .../administer-federation/ingress.md | 311 ---------- .../federation/administer-federation/job.md | 109 ---- .../administer-federation/namespaces.md | 92 --- .../administer-federation/replicaset.md | 132 ---- .../administer-federation/secret.md | 93 --- .../federation-service-discovery.md | 416 ------------- .../set-up-cluster-federation-kubefed.md | 564 ------------------ .../set-up-coredns-provider-federation.md | 152 ----- .../set-up-placement-policies-federation.md | 221 ------- 17 files changed, 2736 deletions(-) delete mode 100755 content/en/docs/tasks/federation/_index.md delete mode 100755 content/en/docs/tasks/federation/administer-federation/_index.md delete mode 100644 content/en/docs/tasks/federation/administer-federation/cluster.md delete mode 100644 content/en/docs/tasks/federation/administer-federation/configmap.md delete mode 100644 content/en/docs/tasks/federation/administer-federation/daemonset.md delete mode 100644 content/en/docs/tasks/federation/administer-federation/deployment.md delete mode 100644 content/en/docs/tasks/federation/administer-federation/events.md delete mode 100644 content/en/docs/tasks/federation/administer-federation/hpa.md delete mode 100644 content/en/docs/tasks/federation/administer-federation/ingress.md delete mode 100644 content/en/docs/tasks/federation/administer-federation/job.md delete mode 100644 content/en/docs/tasks/federation/administer-federation/namespaces.md delete mode 100644 content/en/docs/tasks/federation/administer-federation/replicaset.md delete mode 100644 content/en/docs/tasks/federation/administer-federation/secret.md delete mode 100644 content/en/docs/tasks/federation/federation-service-discovery.md delete mode 100644 content/en/docs/tasks/federation/set-up-cluster-federation-kubefed.md delete mode 100644 content/en/docs/tasks/federation/set-up-coredns-provider-federation.md delete mode 100644 content/en/docs/tasks/federation/set-up-placement-policies-federation.md diff --git a/content/en/docs/tasks/federation/_index.md b/content/en/docs/tasks/federation/_index.md deleted file mode 100755 index 869c63fc6a..0000000000 --- a/content/en/docs/tasks/federation/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Federation" -weight: 120 ---- - diff --git a/content/en/docs/tasks/federation/administer-federation/_index.md b/content/en/docs/tasks/federation/administer-federation/_index.md deleted file mode 100755 index 555416fb9b..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Administer Federation Control Plane" -weight: 160 ---- - diff --git a/content/en/docs/tasks/federation/administer-federation/cluster.md b/content/en/docs/tasks/federation/administer-federation/cluster.md deleted file mode 100644 index 92c1ec5993..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/cluster.md +++ /dev/null @@ -1,119 +0,0 @@ ---- -title: Federated Cluster -content_template: templates/task ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This guide explains how to use Clusters API resource in a Federation control plane. - -Different than other Kubernetes resources, such as Deployments, Services and ConfigMaps, -clusters only exist in the federation context, i.e. those requests must be submitted to the -federation api-server. - -{{% /capture %}} - -{{% capture prerequisites %}} - -* {{< include "federated-task-tutorial-prereqs.md" >}} -* You should also have a basic [working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general. - -{{% /capture %}} - -{{% capture steps %}} - -## Listing Clusters - -To list the clusters available in your federation, you can use [kubectl](/docs/user-guide/kubectl/) by -running: - -``` shell -kubectl --context=federation get clusters -``` - -The `--context=federation` flag tells kubectl to submit the -request to the Federation apiserver instead of sending it to a Kubernetes -cluster. If you submit it to a k8s cluster, you will receive an error saying - -```the server doesn't have a resource type "clusters"``` - -If you passed the correct Federation context but received a message error saying - -```No resources found.``` - -it means that you haven't -added any cluster to the Federation yet. - -## Creating a Federated Cluster - -Creating a `cluster` resource in federation means joining it to the federation. To do so, you can use -`kubefed join`. Basically, you need to give the new cluster a name and say what is the name of the -context that corresponds to a cluster that hosts the federation. The following example command adds -the cluster `gondor` to the federation running on host cluster `rivendell`: - -``` shell -kubefed join gondor --host-cluster-context=rivendell -``` - -You can find more details on how to do that in the respective section in the -[kubefed guide](/docs/tutorials/federation/set-up-cluster-federation-kubefed/#adding-a-cluster-to-a-federation). - -## Deleting a Federated Cluster - -Converse to creating a cluster, deleting a cluster means unjoining this cluster from the -federation. This can be done with `kubefed unjoin` command. To remove the `gondor` cluster, just do: - -``` shell -kubefed unjoin gondor --host-cluster-context=rivendell -``` - -You can find more details on unjoin in the -[kubefed guide](/docs/tutorials/federation/set-up-cluster-federation-kubefed/#removing-a-cluster-from-a-federation). - -## Labeling Clusters - -You can label clusters the same way as any other Kubernetes object, which can help with grouping clusters and can also be leveraged by the ClusterSelector. - -``` shell -kubectl --context=rivendell label cluster gondor key1=value1 key2=value2 -``` - -## ClusterSelector Annotation - -You can use a (deprecated) annotation for directing objects across the federated clusters: `federation.alpha.kubernetes.io/cluster-selector`. The *ClusterSelector* is conceptually similar to `nodeSelector`, but instead of selecting against labels on nodes, it selects against labels on federated clusters. - -The annotation value must be JSON formatted and must be parsable into the [ClusterSelector API type](/docs/reference/federation/v1beta1/definitions/#_v1beta1_clusterselector). For example: `[{"key": "load", "operator": "Lt", "values": ["10"]}]`. Content that doesn't parse correctly will throw an error and prevent distribution of the object to any federated clusters. Objects of type ConfigMap, Secret, Daemonset, Service and Ingress are included in the alpha implementation. - -Here is an example ClusterSelector annotation, which will only select clusters WITH the label `pci=true` and WITHOUT the label `environment=test`: - -``` yaml - metadata: - annotations: - federation.alpha.kubernetes.io/cluster-selector: '[{"key": "pci", "operator": - "In", "values": ["true"]}, {"key": "environment", "operator": "NotIn", "values": - ["test"]}]' -``` - -The *key* is matched against label names on the federated clusters. - -The *values* are matched against the label values on the federated clusters. - -The possible *operators* are: `In`, `NotIn`, `Exists`, `DoesNotExist`, `Gt`, `Lt`. - -The *values* field is expected to be empty when `Exists` or `DoesNotExist` is specified and may include more than one string when `In` or `NotIn` are used. - -Currently, only integers are supported with `Gt` or `Lt`. - -## Clusters API reference - -The full clusters API reference is currently in `federation/v1beta1` and more details can be found in the -[Federation API reference page](/docs/reference/federation/). - -{{% /capture %}} - - diff --git a/content/en/docs/tasks/federation/administer-federation/configmap.md b/content/en/docs/tasks/federation/administer-federation/configmap.md deleted file mode 100644 index b3d0030928..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/configmap.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -title: Federated ConfigMap -content_template: templates/task ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This guide explains how to use ConfigMaps in a Federation control plane. - -Federated ConfigMaps are very similar to the traditional [Kubernetes -ConfigMaps](/docs/tasks/configure-pod-container/configure-pod-configmap/) and provide the same functionality. -Creating them in the federation control plane ensures that they are synchronized -across all the clusters in federation. - -{{% /capture %}} - -{{% capture prerequisites %}} - -* {{< include "federated-task-tutorial-prereqs.md" >}} -* You should also have a basic -[working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general and [ConfigMaps](/docs/tasks/configure-pod-container/configure-pod-configmap/) in particular. - -{{% /capture %}} - -{{% capture steps %}} - -## Creating a Federated ConfigMap - -The API for Federated ConfigMap is 100% compatible with the -API for traditional Kubernetes ConfigMap. You can create a ConfigMap by sending -a request to the federation apiserver. - -You can do that using [kubectl](/docs/user-guide/kubectl/) by running: - -``` shell -kubectl --context=federation-cluster create -f myconfigmap.yaml -``` - -The `--context=federation-cluster` flag tells kubectl to submit the -request to the Federation apiserver instead of sending it to a Kubernetes -cluster. - -Once a Federated ConfigMap is created, the federation control plane will create -a matching ConfigMap in all underlying Kubernetes clusters. -You can verify this by checking each of the underlying clusters, for example: - -``` shell -kubectl --context=gce-asia-east1a get configmap myconfigmap -``` - -The above assumes that you have a context named 'gce-asia-east1a' -configured in your client for your cluster in that zone. - -These ConfigMaps in underlying clusters will match the Federated ConfigMap. - - -## Updating a Federated ConfigMap - -You can update a Federated ConfigMap as you would update a Kubernetes -ConfigMap; however, for a Federated ConfigMap, you must send the request to -the federation apiserver instead of sending it to a specific Kubernetes cluster. -The federation control plane ensures that whenever the Federated ConfigMap is -updated, it updates the corresponding ConfigMaps in all underlying clusters to -match it. - -## Deleting a Federated ConfigMap - -You can delete a Federated ConfigMap as you would delete a Kubernetes -ConfigMap; however, for a Federated ConfigMap, you must send the request to -the federation apiserver instead of sending it to a specific Kubernetes cluster. - -For example, you can do that using kubectl by running: - -```shell -kubectl --context=federation-cluster delete configmap -``` - -{{< note >}} -Deleting a Federated ConfigMap does not delete the corresponding ConfigMaps from underlying clusters. You must delete the underlying ConfigMaps manually. -{{< /note >}} - -{{% /capture %}} - - diff --git a/content/en/docs/tasks/federation/administer-federation/daemonset.md b/content/en/docs/tasks/federation/administer-federation/daemonset.md deleted file mode 100644 index eb93818779..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/daemonset.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -title: Federated DaemonSet -content_template: templates/task ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This guide explains how to use DaemonSets in a federation control plane. - -DaemonSets in the federation control plane ("Federated Daemonsets" in -this guide) are very similar to the traditional Kubernetes -[DaemonSets](/docs/concepts/workloads/controllers/daemonset/) and provide the same functionality. -Creating them in the federation control plane ensures that they are synchronized -across all the clusters in federation. -{{% /capture %}} - -{{% capture prerequisites %}} - -* {{< include "federated-task-tutorial-prereqs.md" >}} -* You should also have a basic -[working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general and [DaemonSets](/docs/concepts/workloads/controllers/daemonset/) in particular. - -{{% /capture %}} - -{{% capture steps %}} - -## Creating a Federated Daemonset - -The API for Federated Daemonset is 100% compatible with the -API for traditional Kubernetes DaemonSet. You can create a DaemonSet by sending -a request to the federation apiserver. - -You can do that using [kubectl](/docs/user-guide/kubectl/) by running: - -``` shell -kubectl --context=federation-cluster create -f mydaemonset.yaml -``` - -The `--context=federation-cluster` flag tells kubectl to submit the -request to the Federation apiserver instead of sending it to a Kubernetes -cluster. - -Once a Federated Daemonset is created, the federation control plane will create -a matching DaemonSet in all underlying Kubernetes clusters. -You can verify this by checking each of the underlying clusters, for example: - -``` shell -kubectl --context=gce-asia-east1a get daemonset mydaemonset -``` - -The above assumes that you have a context named 'gce-asia-east1a' -configured in your client for your cluster in that zone. - - -## Updating a Federated Daemonset - -You can update a Federated Daemonset as you would update a Kubernetes -DaemonSet; however, for a Federated Daemonset, you must send the request to -the federation apiserver instead of sending it to a specific Kubernetes cluster. -The federation control plane ensures that whenever the Federated Daemonset is -updated, it updates the corresponding DaemonSets in all underlying clusters to -match it. - -## Deleting a Federated Daemonset - -You can delete a Federated Daemonset as you would delete a Kubernetes -DaemonSet; however, for a Federated Daemonset, you must send the request to -the federation apiserver instead of sending it to a specific Kubernetes cluster. - -For example, you can do that using kubectl by running: - -```shell -kubectl --context=federation-cluster delete daemonset mydaemonset -``` - -{{% /capture %}} - - diff --git a/content/en/docs/tasks/federation/administer-federation/deployment.md b/content/en/docs/tasks/federation/administer-federation/deployment.md deleted file mode 100644 index 5fd3feb688..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/deployment.md +++ /dev/null @@ -1,111 +0,0 @@ ---- -title: Federated Deployment -content_template: templates/task ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This guide explains how to use Deployments in the Federation control plane. - -Deployments in the federation control plane (referred to as "Federated Deployments" in -this guide) are very similar to the traditional [Kubernetes -Deployment](/docs/concepts/workloads/controllers/deployment/) and provide the same functionality. -Creating them in the federation control plane ensures that the desired number of -replicas exist across the registered clusters. - -{{< feature-state for_k8s_version="1.5" state="alpha" >}} - -Some features -(such as full rollout compatibility) are still in development. -{{% /capture %}} - -{{% capture prerequisites %}} - -* {{< include "federated-task-tutorial-prereqs.md" >}} -* You should also have a basic -[working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general and [Deployments](/docs/concepts/workloads/controllers/deployment/) in particular. - -{{% /capture %}} - -{{% capture steps %}} -## Creating a Federated Deployment - -The API for Federated Deployment is compatible with the -API for traditional Kubernetes Deployment. You can create a Deployment by sending -a request to the federation apiserver. - -You can do that using [kubectl](/docs/user-guide/kubectl/) by running: - -``` shell -kubectl --context=federation-cluster create -f mydeployment.yaml -``` - -The `--context=federation-cluster` flag tells kubectl to submit the -request to the Federation apiserver instead of sending it to a Kubernetes -cluster. - -Once a Federated Deployment is created, the federation control plane will create -a Deployment in all underlying Kubernetes clusters. -You can verify this by checking each of the underlying clusters, for example: - -``` shell -kubectl --context=gce-asia-east1a get deployment mydep -``` - -The above assumes that you have a context named 'gce-asia-east1a' -configured in your client for your cluster in that zone. - -These Deployments in underlying clusters will match the federation Deployment -_except_ in the number of replicas and revision-related annotations. -Federation control plane ensures that the -sum of replicas in each cluster combined matches the desired number of replicas in the -Federated Deployment. - -### Spreading Replicas in Underlying Clusters - -By default, replicas are spread equally in all the underlying clusters. For example: -if you have 3 registered clusters and you create a Federated Deployment with -`spec.replicas = 9`, then each Deployment in the 3 clusters will have -`spec.replicas=3`. -To modify the number of replicas in each cluster, you can specify -[FederatedReplicaSetPreference](https://github.com/kubernetes/federation/blob/{{< param "githubbranch" >}}/apis/federation/types.go) -as an annotation with key `federation.kubernetes.io/deployment-preferences` -on Federated Deployment. - - -## Updating a Federated Deployment - -You can update a Federated Deployment as you would update a Kubernetes -Deployment; however, for a Federated Deployment, you must send the request to -the federation apiserver instead of sending it to a specific Kubernetes cluster. -The federation control plane ensures that whenever the Federated Deployment is -updated, it updates the corresponding Deployments in all underlying clusters to -match it. So if the rolling update strategy was chosen then the underlying -cluster will do the rolling update independently and `maxSurge` and `maxUnavailable` -will apply only to individual clusters. This behavior may change in the future. - -If your update includes a change in number of replicas, the federation -control plane will change the number of replicas in underlying clusters to -ensure that their sum remains equal to the number of desired replicas in -Federated Deployment. - -## Deleting a Federated Deployment - -You can delete a Federated Deployment as you would delete a Kubernetes -Deployment; however, for a Federated Deployment, you must send the request to -the federation apiserver instead of sending it to a specific Kubernetes cluster. - -For example, you can do that using kubectl by running: - -```shell -kubectl --context=federation-cluster delete deployment mydep -``` - -{{% /capture %}} - - diff --git a/content/en/docs/tasks/federation/administer-federation/events.md b/content/en/docs/tasks/federation/administer-federation/events.md deleted file mode 100644 index a7358de478..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/events.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: Federated Events -content_template: templates/concept ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This guide explains how to use events in federation control plane to help in debugging. - -{{% /capture %}} - - -{{% capture body %}} - -## Prerequisites - -This guide assumes that you have a running Kubernetes Cluster -Federation installation. If not, then head over to the -[federation admin guide](/docs/concepts/cluster-administration/federation/) to learn how to -bring up a cluster federation (or have your cluster administrator do -this for you). Other tutorials, for example -[this one](https://github.com/kelseyhightower/kubernetes-cluster-federation) -by Kelsey Hightower, are also available to help you. - -You should also have a basic -[working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general. - -## View federation events - -Events in federation control plane (referred to as "federation events" in -this guide) are very similar to the traditional Kubernetes -Events providing the same functionality. -Federation Events are stored only in federation control plane and are not passed on to the underlying Kubernetes clusters. - -Federation controllers create events as they process API resources to surface to the -user, the state that they are in. -You can get all events from federation apiserver by running: - -```shell -kubectl --context=federation-cluster get events -``` - -The standard kubectl get, update, delete commands will all work. - -{{% /capture %}} diff --git a/content/en/docs/tasks/federation/administer-federation/hpa.md b/content/en/docs/tasks/federation/administer-federation/hpa.md deleted file mode 100644 index 45ed7a3723..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/hpa.md +++ /dev/null @@ -1,184 +0,0 @@ ---- -title: Federated Horizontal Pod Autoscalers (HPA) -content_template: templates/task ---- - -{{% capture overview %}} - -{{< feature-state state="alpha" >}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This guide explains how to use federated horizontal pod autoscalers (HPAs) in the federation control plane. - -HPAs in the federation control plane are similar to the traditional [Kubernetes -HPAs](/docs/tasks/run-application/horizontal-pod-autoscale/), and provide the same functionality. -Creating an HPA targeting a federated object in the federation control plane ensures that the -desired number of replicas of the target object are scaled across the registered clusters, -instead of a single cluster. Also, the control plane keeps monitoring the status of each -individual HPA in the federated clusters and ensures the workload replicas move where they are -needed most by manipulating the min and max limits of the HPA objects in the federated clusters. -{{% /capture %}} - -{{% capture prerequisites %}} - -* {{< include "federated-task-tutorial-prereqs.md" >}} -* You should also have a basic -[working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general and [HPAs](/docs/tasks/run-application/horizontal-pod-autoscale/) in particular. - -The federated HPA is an alpha feature. The API is not enabled by default on the -federated API server. To use this feature, the user or the admin deploying the federation control -plane needs to run the federated API server with option `--runtime-config=api/all=true` to -enable all APIs, including alpha APIs. Additionally, the federated HPA only works -when used with CPU utilization metrics. -{{% /capture %}} - -{{% capture steps %}} - -## Creating a federated HPA - -The API for federated HPAs is 100% compatible with the -API for traditional Kubernetes HPA. You can create an HPA by sending -a request to the federation API server. - -You can do that with [kubectl](/docs/user-guide/kubectl/) by running: - -```shell -cat <}} -A particular cluster cannot have a minimum replica sum of 0. -{{< /note >}} - -### Spreading HPA min and max replicas in underlying clusters - -By default, first max replicas are spread equally in all the underlying clusters, then min replicas are distributed to those clusters that received their maximum value. This means -that each cluster will get an HPA if the specified max replicas are greater than -the total clusters participating in this federation, and some clusters will be -skipped if specified max replicas are less than the total clusters participating -in the federation. - -For example: if you have 3 registered clusters and you create a federated HPA with -`spec.maxReplicas = 9`, and `spec.minReplicas = 2`, then each HPA in the 3 clusters -will get `spec.maxReplicas=3` and `spec.minReplicas = 1`. - -Currently the default distribution is only available on the federated HPA, but in the -future, users preferences could also be specified to control and/or restrict this -distribution. - -## Updating a federated HPA - -You can update a federated HPA as you would update a Kubernetes -HPA; however, for a federated HPA, you must send the request to -the federation API server instead of sending it to a specific Kubernetes cluster. -The Federation control plane ensures that whenever the federated HPA is -updated, it updates the corresponding HPA in all underlying clusters to -match it. - -If your update includes a change in the number of replicas, the federation -control plane will change the number of replicas in underlying clusters to -ensure that the sum of the max and min replicas remains matched as specified -in the previous section. - -## Deleting a federated HPA - -You can delete a federated HPA as you would delete a Kubernetes -HPA; however, for a federated HPA, you must send the request to -the federation API server instead of to a specific Kubernetes cluster. - -{{< note >}} -For the federated resource to be deleted from all underlying clusters, [cascading deletion](/docs/concepts/cluster-administration/federation/#cascading-deletion) should be used. -{{< /note >}} - -For example, you can do that using `kubectl` by running: - -```shell -kubectl --context=federation-cluster delete HPA php-apache -``` - -## Alternative ways to use federated HPA - -To a federation user interacting with federated control plane (or simply federation), -the interaction is almost identical to interacting with a normal Kubernetes cluster (but -with a limited set of APIs that are federated). As both Deployments and -HorizontalPodAutoscalers are now federated, `kubectl` commands like `kubectl run` -and `kubectl autoscale` work on federation. Given this fact, the mechanism specified in -[horizontal pod autoscaler walkthrough](/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/) -will also work when used with federation. -Care however will need to be taken that when -[generating load on a target deployment](/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#step-three-increase-load), -it should be done against a specific federated cluster (or multiple clusters) not the federation. - -## Conclusion - -The use of federated HPA is to ensure workload replicas move to the cluster(s) where -they are needed most, or in other words where the load is beyond expected threshold. -The federated HPA feature achieves this by manipulating the min and max replicas on the -HPAs it creates in the federated clusters. It does not directly monitor the target -object metrics from the federated clusters. It actually relies on the in-cluster HPA -controllers to monitor the metrics and update relevant fields. The in-cluster HPA -controller monitors the target pod metrics and updates the fields like desired -replicas (after metrics based calculations) and current replicas (observing the -current status of in cluster pods). The federated HPA controller, on the other hand, -monitors only the cluster-specific HPA object fields and updates the min replica and -max replica fields of those in cluster HPA objects, which have replicas matching thresholds. - -For example, if a cluster has both desired replicas and current replicas the same as the max replicas, -and averaged current CPU utilization still higher than the target CPU utilization (all of which -are fields on local HPA object), then the target app in this cluster -needs more replicas, and the scaling is currently restricted by max replicas set on this local -HPA object. In such a scenario, the federated HPA controller scans all clusters and tries to -find clusters which do not have such a condition (meaning the desired replicas are less -than the max, and current averaged CPU utilization is lower then the threshold). If it finds such -a cluster, it reduces the max replica on the HPA in this cluster and increases the max replicas -on the HPA in the cluster which needed the replicas. - -There are many other similar conditions which the federated HPA controller checks and moves the max -replicas and min replicas around the local HPAs in federated clusters to eventually ensure that -the replicas move (or remain) in the cluster(s) which need them. - -For more information, see ["federated HPA design proposal"](https://github.com/kubernetes/community/pull/593). - -{{% /capture %}} - - diff --git a/content/en/docs/tasks/federation/administer-federation/ingress.md b/content/en/docs/tasks/federation/administer-federation/ingress.md deleted file mode 100644 index 9d48987d5b..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/ingress.md +++ /dev/null @@ -1,311 +0,0 @@ ---- -title: Federated Ingress -content_template: templates/task ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This page explains how to use Kubernetes Federated Ingress to deploy -a common HTTP(S) virtual IP load balancer across a federated service running in -multiple Kubernetes clusters. As of v1.4, clusters hosted in Google -Cloud (both Google Kubernetes Engine and GCE, or both) are supported. This makes it -easy to deploy a service that reliably serves HTTP(S) traffic -originating from web clients around the globe on a single, static IP -address. Low network latency, high fault tolerance and easy administration are -ensured through intelligent request routing and automatic replica -relocation (using [Federated ReplicaSets](/docs/tasks/administer-federation/replicaset/). -Clients are automatically routed, via the shortest network path, to -the cluster closest to them with available capacity (despite the fact -that all clients use exactly the same static IP address). The load balancer -automatically checks the health of the pods comprising the service, -and avoids sending requests to unresponsive or slow pods (or entire -unresponsive clusters). - -Federated Ingress is released as an alpha feature, and supports Google Cloud Platform (Google Kubernetes Engine, -GCE and hybrid scenarios involving both) in Kubernetes v1.4. Work is under way to support other cloud -providers such as AWS, and other hybrid cloud scenarios (e.g. services -spanning private on-premises as well as public cloud Kubernetes -clusters). - -You create Federated Ingresses in much that same way as traditional -[Kubernetes Ingresses](/docs/concepts/services-networking/ingress/): by making an API -call which specifies the desired properties of your logical ingress point. In the -case of Federated Ingress, this API call is directed to the -Federation API endpoint, rather than a Kubernetes cluster API -endpoint. The API for Federated Ingress is 100% compatible with the -API for traditional Kubernetes Services. - -Once created, the Federated Ingress automatically: - -* Creates matching Kubernetes Ingress objects in every cluster underlying your Cluster Federation -* Ensures that all of these in-cluster ingress objects share the same - logical global L7 (that is, HTTP(S)) load balancer and IP address -* Monitors the health and capacity of the service shards (that is, your pods) behind this ingress in each cluster -* Ensures that all client connections are routed to an appropriate healthy backend service endpoint at all times, even in the event of pod, cluster, availability zone or regional outages - -Note that in the case of Google Cloud, the logical L7 load balancer is -not a single physical device (which would present both a single point -of failure, and a single global network routing choke point), but -rather a -[truly global, highly available load balancing managed service](https://cloud.google.com/load-balancing/), -globally reachable via a single, static IP address. - -Clients inside your federated Kubernetes clusters (Pods) will be -automatically routed to the cluster-local shard of the Federated Service -backing the Ingress in their cluster if it exists and is healthy, or the closest healthy shard in a -different cluster if it does not. Note that this involves a network -trip to the HTTP(s) load balancer, which resides outside your local -Kubernetes cluster but inside the same GCP region. -{{% /capture %}} - -{{% capture prerequisites %}} -This document assumes that you have a running Kubernetes Cluster -Federation installation. If not, then see the -[federation admin guide](/docs/tasks/federation/set-up-cluster-federation-kubefed/) to learn how to -bring up a cluster federation (or have your cluster administrator do -this for you). Other tutorials, for example -[this one](https://github.com/kelseyhightower/kubernetes-cluster-federation) -by Kelsey Hightower, are also available to help you. - -You should also have a basic -[working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general, and [Ingress](/docs/concepts/services-networking/ingress/) in particular. -{{% /capture %}} - -{{% capture steps %}} -## Creating a federated ingress - -You can create a federated ingress in any of the usual ways, for example, using kubectl: - -``` shell -kubectl --context=federation-cluster create -f myingress.yaml -``` -For example ingress YAML configurations, see the [Ingress User Guide](/docs/concepts/services-networking/ingress/). -The `--context=federation-cluster` flag tells kubectl to submit the -request to the Federation API endpoint, with the appropriate -credentials. If you have not yet configured such a context, see the -[federation admin guide](/docs/admin/federation/) or one of the -[administration tutorials](https://github.com/kelseyhightower/kubernetes-cluster-federation) -to find out how to do so. - -The Federated Ingress automatically creates -and maintains matching Kubernetes ingresses in all of the clusters -underlying your federation. These cluster-specific ingresses (and -their associated ingress controllers) configure and manage the load -balancing and health checking infrastructure that ensures that traffic -is load balanced to each cluster appropriately. - -You can verify this by checking in each of the underlying clusters. For example: - -``` shell -kubectl --context=gce-asia-east1a get ingress myingress -NAME HOSTS ADDRESS PORTS AGE -myingress * 130.211.5.194 80, 443 1m -``` - -The above assumes that you have a context named 'gce-asia-east1a' -configured in your client for your cluster in that zone. The name and -namespace of the underlying ingress automatically matches those of -the Federated Ingress that you created above (and if you happen to -have had ingresses of the same name and namespace already existing in -any of those clusters, they will be automatically adopted by the -Federation and updated to conform with the specification of your -Federated Ingress. Either way, the end result will be the same). - -The status of your Federated Ingress automatically reflects the -real-time status of the underlying Kubernetes ingresses. For example: - -``` shell -kubectl --context=federation-cluster describe ingress myingress - -Name: myingress -Namespace: default -Address: 130.211.5.194 -TLS: - tls-secret terminates -Rules: - Host Path Backends - ---- ---- -------- - * * echoheaders-https:80 (10.152.1.3:8080,10.152.2.4:8080) -Annotations: - https-target-proxy: k8s-tps-default-myingress--ff1107f83ed600c0 - target-proxy: k8s-tp-default-myingress--ff1107f83ed600c0 - url-map: k8s-um-default-myingress--ff1107f83ed600c0 - backends: {"k8s-be-30301--ff1107f83ed600c0":"Unknown"} - forwarding-rule: k8s-fw-default-myingress--ff1107f83ed600c0 - https-forwarding-rule: k8s-fws-default-myingress--ff1107f83ed600c0 -Events: - FirstSeen LastSeen Count From SubobjectPath Type Reason Message - --------- -------- ----- ---- ------------- -------- ------ ------- - 3m 3m 1 {loadbalancer-controller } Normal ADD default/myingress - 2m 2m 1 {loadbalancer-controller } Normal CREATE ip: 130.211.5.194 -``` - -Note that: - -* The address of your Federated Ingress -corresponds with the address of all of the -underlying Kubernetes ingresses (once these have been allocated - this -may take up to a few minutes). -* You have not yet provisioned any backend Pods to receive -the network traffic directed to this ingress (that is, 'Service -Endpoints' behind the service backing the Ingress), so the Federated Ingress does not yet consider these to -be healthy shards and will not direct traffic to any of these clusters. -* The federation control system -automatically reconfigures the load balancer controllers in all of the -clusters in your federation to make them consistent, and allows -them to share global load balancers. But this reconfiguration can -only complete successfully if there are no pre-existing Ingresses in -those clusters (this is a safety feature to prevent accidental -breakage of existing ingresses). So, to ensure that your federated -ingresses function correctly, either start with new, empty clusters, or make -sure that you delete (and recreate if necessary) all pre-existing -Ingresses in the clusters comprising your federation. - -## Adding backend services and pods - -To render the underlying ingress shards healthy, you need to add -backend Pods behind the service upon which the Ingress is based. There are several ways to achieve this, but -the easiest is to create a Federated Service and -Federated ReplicaSet. To -create appropriately labelled pods and services in the 13 underlying clusters of -your federation: - -``` shell -kubectl --context=federation-cluster create -f services/nginx.yaml -``` - -``` shell -kubectl --context=federation-cluster create -f myreplicaset.yaml -``` - -Note that in order for your federated ingress to work correctly on -Google Cloud, the node ports of all of the underlying cluster-local -services need to be identical. If you're using a federated service -this is easy to do. Simply pick a node port that is not already -being used in any of your clusters, and add that to the spec of your -federated service. If you do not specify a node port for your -federated service, each cluster will choose its own node port for -its cluster-local shard of the service, and these will probably end -up being different, which is not what you want. - -You can verify this by checking in each of the underlying clusters. For example: - -``` shell -kubectl --context=gce-asia-east1a get services nginx -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -nginx ClusterIP 10.63.250.98 104.199.136.89 80/TCP 9m -``` - -## Hybrid cloud capabilities - -Federations of Kubernetes Clusters can include clusters running in -different cloud providers (for example, Google Cloud, AWS), and on-premises -(for example, on OpenStack). However, in Kubernetes v1.4, Federated Ingress is only -supported across Google Cloud clusters. - -## Discovering a federated ingress - -Ingress objects (in both plain Kubernetes clusters, and in federations -of clusters) expose one or more IP addresses (via -the Status.Loadbalancer.Ingress field) that remains static for the lifetime -of the Ingress object (in future, automatically managed DNS names -might also be added). All clients (whether internal to your cluster, -or on the external network or internet) should connect to one of these IP -or DNS addresses. All client requests are automatically -routed, via the shortest network path, to a healthy pod in the -closest cluster to the origin of the request. So for example, HTTP(S) -requests from internet -users in Europe will be routed directly to the closest cluster in -Europe that has available capacity. If there are no such clusters in -Europe, the request will be routed to the next closest cluster -(typically in the U.S.). - -## Handling failures of backend pods and whole clusters - -Ingresses are backed by Services, which are typically (but not always) -backed by one or more ReplicaSets. For Federated Ingresses, it is -common practise to use the federated variants of Services and -ReplicaSets for this purpose. - -In particular, Federated ReplicaSets ensure that the desired number of -pods are kept running in each cluster, even in the event of node -failures. In the event of entire cluster or availability zone -failures, Federated ReplicaSets automatically place additional -replicas in the other available clusters in the federation to accommodate the -traffic which was previously being served by the now unavailable -cluster. While the Federated ReplicaSet ensures that sufficient replicas are -kept running, the Federated Ingress ensures that user traffic is -automatically redirected away from the failed cluster to other -available clusters. - -## Troubleshooting - -#### I cannot connect to my cluster federation API. - -Check that your: - -1. Client (typically `kubectl`) is correctly configured (including API endpoints and login credentials). -2. Cluster Federation API server is running and network-reachable. - -See the [federation admin guide](/docs/admin/federation/) to learn -how to bring up a cluster federation correctly (or have your cluster administrator do this for you), and how to correctly configure your client. - -#### I can create a Federated Ingress/service/replicaset successfully against the cluster federation API, but no matching ingresses/services/replicasets are created in my underlying clusters. - -Check that: - -1. Your clusters are correctly registered in the Cluster Federation API. (`kubectl describe clusters`) -2. Your clusters are all 'Active'. This means that the cluster - Federation system was able to connect and authenticate against the - clusters' endpoints. If not, consult the event logs of the federation-controller-manager pod to ascertain what the failure might be. (`kubectl --namespace=federation logs $(kubectl get pods --namespace=federation -l module=federation-controller-manager -o name`) -3. That the login credentials provided to the Cluster Federation API - for the clusters have the correct authorization and quota to create - ingresses/services/replicasets in the relevant namespace in the - clusters. Again you should see associated error messages providing - more detail in the above event log file if this is not the case. -4. Whether any other error is preventing the service creation - operation from succeeding (look for `ingress-controller`, - `service-controller` or `replicaset-controller`, - errors in the output of `kubectl logs federation-controller-manager --namespace federation`). - -#### I can create a federated ingress successfully, but request load is not correctly distributed across the underlying clusters. - -Check that: - -1. The services underlying your federated ingress in each cluster have - identical node ports. See [above](#creating_a_federated_ingress) for further explanation. -2. The load balancer controllers in each of your clusters are of the - correct type ("GLBC") and have been correctly reconfigured by the - federation control plane to share a global GCE load balancer (this - should happen automatically). If they are of the correct type, and - have been correctly reconfigured, the UID data item in the GLBC - configmap in each cluster will be identical across all clusters. - See - [the GLBC docs](https://github.com/kubernetes/ingress/blob/7dcb4ae17d5def23d3e9c878f3146ac6df61b09d/controllers/gce/README.md) - for further details. - If this is not the case, check the logs of your federation - controller manager to determine why this automated reconfiguration - might be failing. -3. No ingresses have been manually created in any of your clusters before the above - reconfiguration of the load balancer controller completed - successfully. Ingresses created before the reconfiguration of - your GLBC will interfere with the behavior of your federated - ingresses created after the reconfiguration (see - [the GLBC docs](https://github.com/kubernetes/ingress/blob/7dcb4ae17d5def23d3e9c878f3146ac6df61b09d/controllers/gce/README.md) - for further information). To remedy this, - delete any ingresses created before the cluster joined the - federation (and had its GLBC reconfigured), and recreate them if - necessary. -{{% /capture %}} - -{{% capture whatsnext %}} -* If you need assistance, use one of the [support channels](/docs/tasks/debug-application-cluster/troubleshooting/) to seek assistance. - * For details about use cases that motivated this work, see - [Federation proposal](https://git.k8s.io/community/contributors/design-proposals/multicluster/federation.md). -{{% /capture %}} - diff --git a/content/en/docs/tasks/federation/administer-federation/job.md b/content/en/docs/tasks/federation/administer-federation/job.md deleted file mode 100644 index 5b921fe3f6..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/job.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -title: Federated Jobs -content_template: templates/task ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This guide explains how to use jobs in the federation control plane. - -Jobs in the federation control plane (referred to as "federated jobs" in -this guide) are similar to the traditional [Kubernetes -jobs](/docs/concepts/workloads/controllers/job/), and provide the same functionality. -Creating jobs in the federation control plane ensures that the desired number of -parallelism and completions exist across the registered clusters. -{{% /capture %}} - -{{% capture prerequisites %}} - -* {{< include "federated-task-tutorial-prereqs.md" >}} -* You should also have a basic -[working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general and [jobs](/docs/concepts/workloads/controllers/jobs-run-to-completion/) in particular. -{{% /capture %}} - -{{% capture steps %}} - -## Creating a federated job - -The API for federated jobs is fully compatible with the -API for traditional Kubernetes jobs. You can create a job by sending -a request to the federation apiserver. - -You can do that using [kubectl](/docs/user-guide/kubectl/) by running: - -``` shell -kubectl --context=federation-cluster create -f myjob.yaml -``` - -The `--context=federation-cluster` flag tells kubectl to submit the -request to the federation API server instead of sending it to a Kubernetes -cluster. - -Once a federated job is created, the federation control plane creates -a job in all underlying Kubernetes clusters. -You can verify this by checking each of the underlying clusters, for example: - -``` shell -kubectl --context=gce-asia-east1a get job myjob -``` - -The previous example assumes that you have a context named `gce-asia-east1a` -configured in your client for your cluster in that zone. - -The jobs in the underlying clusters match the federated job -except in the number of parallelism and completions. The federation control plane ensures that the -sum of the parallelism and completions in each cluster matches the desired number of parallelism and completions in the -federated job. - -### Spreading job tasks in underlying clusters - -By default, parallelism and completions are spread equally in all underlying clusters. For example: -if you have 3 registered clusters and you create a federated job with -`spec.parallelism = 9` and `spec.completions = 18`, then each job in the 3 clusters has -`spec.parallelism = 3` and `spec.completions = 6`. -To modify the number of parallelism and completions in each cluster, you can specify -[ReplicaAllocationPreferences](https://github.com/kubernetes/federation/blob/{{< param "githubbranch" >}}/apis/federation/types.go) -as an annotation with key `federation.kubernetes.io/job-preferences` -on the federated job. - - -## Updating a federated job - -You can update a federated job as you would update a Kubernetes -job; however, for a federated job, you must send the request to -the federation API server instead of sending it to a specific Kubernetes cluster. -The federation control plane ensures that whenever the federated job is -updated, it updates the corresponding job in all underlying clusters to -match it. - -If your update includes a change in number of parallelism and completions, the federation -control plane changes the number of parallelism and completions in underlying clusters to -ensure that their sum remains equal to the number of desired parallelism and completions in -federated job. - -## Deleting a federated job - -You can delete a federated job as you would delete a Kubernetes -job; however, for a federated job, you must send the request to -the federation API server instead of sending it to a specific Kubernetes cluster. - -For example, with kubectl: - -```shell -kubectl --context=federation-cluster delete job myjob -``` - -{{< note >}} -Deleting a federated job will not delete the -corresponding jobs from underlying clusters. -You must delete the underlying jobs manually. -{{< /note >}} - -{{% /capture %}} - - diff --git a/content/en/docs/tasks/federation/administer-federation/namespaces.md b/content/en/docs/tasks/federation/administer-federation/namespaces.md deleted file mode 100644 index 13c9c5dcaa..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/namespaces.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -title: Federated Namespaces -content_template: templates/task ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This guide explains how to use Namespaces in Federation control plane. - -Namespaces in federation control plane (referred to as "federated Namespaces" in -this guide) are very similar to the traditional [Kubernetes -Namespaces](/docs/concepts/overview/working-with-objects/namespaces/) providing the same functionality. -Creating them in the federation control plane ensures that they are synchronized -across all the clusters in federation. -{{% /capture %}} - -{{% capture prerequisites %}} - -* {{< include "federated-task-tutorial-prereqs.md" >}} -* You are also expected to have a basic -[working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general and [Namespaces](/docs/concepts/overview/working-with-objects/namespaces/) in particular. - -{{% /capture %}} - -{{% capture steps %}} - -## Creating a Federated Namespace - -The API for Federated Namespaces is 100% compatible with the -API for traditional Kubernetes Namespaces. You can create a Namespace by sending -a request to the federation apiserver. - -You can do that using kubectl by running: - -``` shell -kubectl --context=federation-cluster create -f myns.yaml -``` - -The `--context=federation-cluster` flag tells kubectl to submit the -request to the Federation apiserver instead of sending it to a Kubernetes -cluster. - -Once a federated Namespace is created, the federation control plane will create -a matching Namespace in all underlying Kubernetes clusters. -You can verify this by checking each of the underlying clusters, for example: - -``` shell -kubectl --context=gce-asia-east1a get namespaces myns -``` - -The above assumes that you have a context named 'gce-asia-east1a' -configured in your client for your cluster in that zone. The name and -spec of the underlying Namespace will match those of -the Federated Namespace that you created above. - - -## Updating a Federated Namespace - -You can update a federated Namespace as you would update a Kubernetes -Namespace, just send the request to federation apiserver instead of sending it -to a specific Kubernetes cluster. -Federation control plane will ensure that whenever the federated Namespace is -updated, it updates the corresponding Namespaces in all underlying clusters to -match it. - -## Deleting a Federated Namespace - -You can delete a federated Namespace as you would delete a Kubernetes -Namespace, just send the request to federation apiserver instead of sending it -to a specific Kubernetes cluster. - -For example, you can do that using kubectl by running: - -```shell -kubectl --context=federation-cluster delete ns myns -``` - -As in Kubernetes, deleting a federated Namespace will delete all resources in that -Namespace from the federation control plane. - -{{< note >}} -At this point, deleting a federated Namespace will not delete the corresponding Namespace, or resources in those Namespaces, from underlying clusters. Users must delete them manually. We intend to fix this in the future. -{{< /note >}} - -{{% /capture %}} - - diff --git a/content/en/docs/tasks/federation/administer-federation/replicaset.md b/content/en/docs/tasks/federation/administer-federation/replicaset.md deleted file mode 100644 index 1fa5d856a8..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/replicaset.md +++ /dev/null @@ -1,132 +0,0 @@ ---- -title: Federated ReplicaSets -content_template: templates/task ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This guide explains how to use ReplicaSets in the Federation control plane. - -ReplicaSets in the federation control plane (referred to as "federated ReplicaSets" in -this guide) are very similar to the traditional [Kubernetes -ReplicaSets](/docs/concepts/workloads/controllers/replicaset/), and provide the same functionality. -Creating them in the federation control plane ensures that the desired number of -replicas exist across the registered clusters. -{{% /capture %}} - -{{% capture prerequisites %}} - -* {{< include "federated-task-tutorial-prereqs.md" >}} -* You should also have a basic -[working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general and [ReplicaSets](/docs/concepts/workloads/controllers/replicaset/) in particular. -{{% /capture %}} - -{{% capture steps %}} - -## Creating a Federated ReplicaSet - -The API for Federated ReplicaSet is 100% compatible with the -API for traditional Kubernetes ReplicaSet. You can create a ReplicaSet by sending -a request to the federation apiserver. - -You can do that using [kubectl](/docs/user-guide/kubectl/) by running: - -``` shell -kubectl --context=federation-cluster create -f myrs.yaml -``` - -The `--context=federation-cluster` flag tells kubectl to submit the -request to the Federation apiserver instead of sending it to a Kubernetes -cluster. - -Once a federated ReplicaSet is created, the federation control plane will create -a ReplicaSet in all underlying Kubernetes clusters. -You can verify this by checking each of the underlying clusters, for example: - -``` shell -kubectl --context=gce-asia-east1a get rs myrs -``` - -The above assumes that you have a context named 'gce-asia-east1a' -configured in your client for your cluster in that zone. - -The ReplicaSets in the underlying clusters will match the federation ReplicaSet -except in the number of replicas. The federation control plane will ensure that the -sum of the replicas in each cluster match the desired number of replicas in the -federation ReplicaSet. - -### Spreading Replicas in Underlying Clusters - -By default, replicas are spread equally in all the underlying clusters. For example: -if you have 3 registered clusters and you create a federated ReplicaSet with -`spec.replicas = 9`, then each ReplicaSet in the 3 clusters will have -`spec.replicas=3`. -To modify the number of replicas in each cluster, you can add an annotation with -key `federation.kubernetes.io/replica-set-preferences` to the federated ReplicaSet. -The value of the annoation is a serialized JSON that contains fields shown in -the following example: - -``` -{ - "rebalance": true, - "clusters": { - "foo": { - "minReplicas": 10, - "maxReplicas": 50, - "weight": 100 - }, - "bar": { - "minReplicas": 10, - "maxReplicas": 100, - "weight": 200 - } - } -} -``` - -The `rebalance` boolean field specifies whether replicas already scheduled and running -may be moved in order to match current state to the specified preferences. -The `clusters` object field contains a map where users can specify the constraints -for replica placement across the clusters (`foo` and `bar` in the example). -For each cluster, you can specify the minimum number of replicas that should be -assigned to it (default is zero), the maximum number of replicas the cluster can -accept (default is unbounded) and a number expressing the relative weight of -preferences to place additional replicas to that cluster. - -## Updating a Federated ReplicaSet - -You can update a federated ReplicaSet as you would update a Kubernetes -ReplicaSet; however, for a federated ReplicaSet, you must send the request to -the federation apiserver instead of sending it to a specific Kubernetes cluster. -The Federation control plane ensures that whenever the federated ReplicaSet is -updated, it updates the corresponding ReplicaSet in all underlying clusters to -match it. -If your update includes a change in number of replicas, the federation -control plane will change the number of replicas in underlying clusters to -ensure that their sum remains equal to the number of desired replicas in -federated ReplicaSet. - -## Deleting a Federated ReplicaSet - -You can delete a federated ReplicaSet as you would delete a Kubernetes -ReplicaSet; however, for a federated ReplicaSet, you must send the request to -the federation apiserver instead of sending it to a specific Kubernetes cluster. - -For example, you can do that using kubectl by running: - -```shell -kubectl --context=federation-cluster delete rs myrs -``` - -{{< note >}} -At this point, deleting a federated ReplicaSet will not delete the corresponding ReplicaSets from underlying clusters. You must delete the underlying ReplicaSets manually. We intend to fix this in the future. -{{< /note >}} - -{{% /capture %}} - - diff --git a/content/en/docs/tasks/federation/administer-federation/secret.md b/content/en/docs/tasks/federation/administer-federation/secret.md deleted file mode 100644 index d69f48de40..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/secret.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -title: Federated Secrets -content_template: templates/concept ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This guide explains how to use secrets in Federation control plane. - -Secrets in federation control plane (referred to as "federated secrets" in -this guide) are very similar to the traditional [Kubernetes -Secrets](/docs/concepts/configuration/secret/) providing the same functionality. -Creating them in the federation control plane ensures that they are synchronized -across all the clusters in federation. -{{% /capture %}} - - -{{% capture body %}} - -## Prerequisites - -This guide assumes that you have a running Kubernetes Cluster -Federation installation. If not, then head over to the -[federation admin guide](/docs/admin/federation/) to learn how to -bring up a cluster federation (or have your cluster administrator do -this for you). Other tutorials, for example -[this one](https://github.com/kelseyhightower/kubernetes-cluster-federation) -by Kelsey Hightower, are also available to help you. - -You should also have a basic -[working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general and [Secrets](/docs/concepts/configuration/secret/) in particular. - -## Creating a Federated Secret - -The API for Federated Secret is 100% compatible with the -API for traditional Kubernetes Secret. You can create a secret by sending -a request to the federation apiserver. - -You can do that using [kubectl](/docs/user-guide/kubectl/) by running: - -``` shell -kubectl --context=federation-cluster create -f mysecret.yaml -``` - -The `--context=federation-cluster` flag tells kubectl to submit the -request to the Federation apiserver instead of sending it to a Kubernetes -cluster. - -Once a federated secret is created, the federation control plane will create -a matching secret in all underlying Kubernetes clusters. -You can verify this by checking each of the underlying clusters, for example: - -``` shell -kubectl --context=gce-asia-east1a get secret mysecret -``` - -The above assumes that you have a context named 'gce-asia-east1a' -configured in your client for your cluster in that zone. - -These secrets in underlying clusters will match the federated secret. - - -## Updating a Federated Secret - -You can update a federated secret as you would update a Kubernetes -secret; however, for a federated secret, you must send the request to -the federation apiserver instead of sending it to a specific Kubernetes cluster. -The Federation control plane ensures that whenever the federated secret is -updated, it updates the corresponding secrets in all underlying clusters to -match it. - -## Deleting a Federated Secret - -You can delete a federated secret as you would delete a Kubernetes -secret; however, for a federated secret, you must send the request to -the federation apiserver instead of sending it to a specific Kubernetes cluster. - -For example, you can do that using kubectl by running: - -```shell -kubectl --context=federation-cluster delete secret mysecret -``` - -{{< note >}} -At this point, deleting a federated secret will not delete the corresponding secrets from underlying clusters. You must delete the underlying secrets manually. We intend to fix this in the future. -{{< /note >}} - -{{% /capture %}} diff --git a/content/en/docs/tasks/federation/federation-service-discovery.md b/content/en/docs/tasks/federation/federation-service-discovery.md deleted file mode 100644 index 0d6d89e078..0000000000 --- a/content/en/docs/tasks/federation/federation-service-discovery.md +++ /dev/null @@ -1,416 +0,0 @@ ---- -title: Cross-cluster Service Discovery using Federated Services -reviewers: -- bprashanth -- quinton-hoole -content_template: templates/task -weight: 140 ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This guide explains how to use Kubernetes Federated Services to deploy -a common Service across multiple Kubernetes clusters. This makes it -easy to achieve cross-cluster service discovery and availability zone -fault tolerance for your Kubernetes applications. - - -Federated Services are created in much that same way as traditional -[Kubernetes Services](/docs/concepts/services-networking/service/) by making an API -call which specifies the desired properties of your service. In the -case of Federated Services, this API call is directed to the -Federation API endpoint, rather than a Kubernetes cluster API -endpoint. The API for Federated Services is 100% compatible with the -API for traditional Kubernetes Services. - -Once created, the Federated Service automatically: - -1. Creates matching Kubernetes Services in every cluster underlying your Cluster Federation, -2. Monitors the health of those service "shards" (and the clusters in which they reside), and -3. Manages a set of DNS records in a public DNS provider (like Google Cloud DNS, or AWS Route 53), thus ensuring that clients -of your federated service can seamlessly locate an appropriate healthy service endpoint at all times, even in the event of cluster, -availability zone or regional outages. - -Clients inside your federated Kubernetes clusters (that is Pods) will -automatically find the local shard of the Federated Service in their -cluster if it exists and is healthy, or the closest healthy shard in a -different cluster if it does not. - -{{% /capture %}} - -{{< toc >}} - -{{% capture prerequisites %}} - -{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}} - -{{% /capture %}} - -{{% capture steps %}} - -## Prerequisites - -This guide assumes that you have a running Kubernetes Cluster -Federation installation. If not, then head over to the -[federation admin guide](/docs/admin/federation/) to learn how to -bring up a cluster federation (or have your cluster administrator do -this for you). Other tutorials, for example -[this one](https://github.com/kelseyhightower/kubernetes-cluster-federation) -by Kelsey Hightower, are also available to help you. - -You should also have a basic -[working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general, and [Services](/docs/concepts/services-networking/service/) in particular. - -## Hybrid cloud capabilities - -Federations of Kubernetes Clusters can include clusters running in -different cloud providers (such as Google Cloud or AWS), and on-premises -(such as on OpenStack). Simply create all of the clusters that you -require, in the appropriate cloud providers and/or locations, and -register each cluster's API endpoint and credentials with your -Federation API Server (See the -[federation admin guide](/docs/admin/federation/) for details). - -Thereafter, your applications and services can span different clusters -and cloud providers as described in more detail below. - -## Creating a federated service - -This is done in the usual way, for example: - -``` shell -kubectl --context=federation-cluster create -f services/nginx.yaml -``` - -The '--context=federation-cluster' flag tells kubectl to submit the -request to the Federation API endpoint, with the appropriate -credentials. If you have not yet configured such a context, visit the -[federation admin guide](/docs/admin/federation/) or one of the -[administration tutorials](https://github.com/kelseyhightower/kubernetes-cluster-federation) -to find out how to do so. - -As described above, the Federated Service will automatically create -and maintain matching Kubernetes services in all of the clusters -underlying your federation. - -You can verify this by checking in each of the underlying clusters, for example: - -``` shell -kubectl --context=gce-asia-east1a get services nginx -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -nginx ClusterIP 10.63.250.98 104.199.136.89 80/TCP 9m -``` - -The above assumes that you have a context named 'gce-asia-east1a' -configured in your client for your cluster in that zone. The name and -namespace of the underlying services will automatically match those of -the Federated Service that you created above (and if you happen to -have had services of the same name and namespace already existing in -any of those clusters, they will be automatically adopted by the -Federation and updated to conform with the specification of your -Federated Service - either way, the end result will be the same). - -The status of your Federated Service will automatically reflect the -real-time status of the underlying Kubernetes services, for example: - -``` shell -kubectl --context=federation-cluster describe services nginx -``` -``` -Name: nginx -Namespace: default -Labels: run=nginx -Annotations: -Selector: run=nginx -Type: LoadBalancer -IP: 10.63.250.98 -LoadBalancer Ingress: 104.197.246.190, 130.211.57.243, 104.196.14.231, 104.199.136.89, ... -Port: http 80/TCP -Endpoints: -Session Affinity: None -Events: -``` - -{{< note >}} -The 'LoadBalancer Ingress' addresses of your Federated Service -correspond with the 'LoadBalancer Ingress' addresses of all of the -underlying Kubernetes services (once these have been allocated - this -may take a few seconds). For inter-cluster and inter-cloud-provider -networking between service shards to work correctly, your services -need to have an externally visible IP address. [Service Type: -Loadbalancer](/docs/concepts/services-networking/service/#loadbalancer) -is typically used for this, although other options -(for example [External IPs](/docs/concepts/services-networking/service/#external-ips)) exist. -{{< /note >}} - -Note also that we have not yet provisioned any backend Pods to receive -the network traffic directed to these addresses (that is 'Service -Endpoints'), so the Federated Service does not yet consider these to -be healthy service shards, and has accordingly not yet added their -addresses to the DNS records for this Federated Service (more on this -aspect later). - -## Adding backend pods - -To render the underlying service shards healthy, we need to add -backend Pods behind them. This is currently done directly against the -API endpoints of the underlying clusters (although in future the -Federation server will be able to do all this for you with a single -command, to save you the trouble). For example, to create backend Pods -in 13 underlying clusters: - -``` shell -for CLUSTER in asia-east1-c asia-east1-a asia-east1-b \ - europe-west1-d europe-west1-c europe-west1-b \ - us-central1-f us-central1-a us-central1-b us-central1-c \ - us-east1-d us-east1-c us-east1-b -do - kubectl --context=$CLUSTER run nginx --image=nginx:1.11.1-alpine --port=80 -done -``` - -Note that `kubectl run` automatically adds the `run=nginx` labels required to associate the backend pods with their services. - -## Verifying public DNS records - -Once the above Pods have successfully started and have begun listening -for connections, Kubernetes will report them as healthy endpoints of -the service in that cluster (through automatic health checks). The Cluster -Federation will in turn consider each of these -service 'shards' to be healthy, and place them in serving by -automatically configuring corresponding public DNS records. You can -use your preferred interface to your configured DNS provider to verify -this. For example, if your Federation is configured to use Google -Cloud DNS, and a managed DNS domain 'example.com': - -``` shell -gcloud dns managed-zones describe example-dot-com -``` -``` -creationTime: '2016-06-26T18:18:39.229Z' -description: Example domain for Kubernetes Cluster Federation -dnsName: example.com. -id: '3229332181334243121' -kind: dns#managedZone -name: example-dot-com -nameServers: -- ns-cloud-a1.googledomains.com. -- ns-cloud-a2.googledomains.com. -- ns-cloud-a3.googledomains.com. -- ns-cloud-a4.googledomains.com. -``` - -```shell -gcloud dns record-sets list --zone example-dot-com -``` -``` -NAME TYPE TTL DATA -example.com. NS 21600 ns-cloud-e1.googledomains.com., ns-cloud-e2.googledomains.com. -example.com. OA 21600 ns-cloud-e1.googledomains.com. cloud-dns-hostmaster.google.com. 1 21600 3600 1209600 300 -nginx.mynamespace.myfederation.svc.example.com. A 180 104.197.246.190, 130.211.57.243, 104.196.14.231, 104.199.136.89,... -nginx.mynamespace.myfederation.svc.us-central1-a.example.com. A 180 104.197.247.191 -nginx.mynamespace.myfederation.svc.us-central1-b.example.com. A 180 104.197.244.180 -nginx.mynamespace.myfederation.svc.us-central1-c.example.com. A 180 104.197.245.170 -nginx.mynamespace.myfederation.svc.us-central1-f.example.com. CNAME 180 nginx.mynamespace.myfederation.svc.us-central1.example.com. -nginx.mynamespace.myfederation.svc.us-central1.example.com. A 180 104.197.247.191, 104.197.244.180, 104.197.245.170 -nginx.mynamespace.myfederation.svc.asia-east1-a.example.com. A 180 130.211.57.243 -nginx.mynamespace.myfederation.svc.asia-east1-b.example.com. CNAME 180 nginx.mynamespace.myfederation.svc.asia-east1.example.com. -nginx.mynamespace.myfederation.svc.asia-east1-c.example.com. A 180 130.211.56.221 -nginx.mynamespace.myfederation.svc.asia-east1.example.com. A 180 130.211.57.243, 130.211.56.221 -nginx.mynamespace.myfederation.svc.europe-west1.example.com. CNAME 180 nginx.mynamespace.myfederation.svc.example.com. -nginx.mynamespace.myfederation.svc.europe-west1-d.example.com. CNAME 180 nginx.mynamespace.myfederation.svc.europe-west1.example.com. -... etc. -``` - -{{< note >}} -If your Federation is configured to use AWS Route53, you can use one of the equivalent AWS tools, for example: - -``` shell -aws route53 list-hosted-zones -``` -and - -``` shell -aws route53 list-resource-record-sets --hosted-zone-id Z3ECL0L9QLOVBX -``` -{{< /note >}} - -Whatever DNS provider you use, any DNS query tool (for example 'dig' -or 'nslookup') will of course also allow you to see the records -created by the Federation for you. Note that you should either point -these tools directly at your DNS provider (such as `dig -@ns-cloud-e1.googledomains.com...`) or expect delays in the order of -your configured TTL (180 seconds, by default) before seeing updates, -due to caching by intermediate DNS servers. - -### Some notes about the above example - -1. Notice that there is a normal ('A') record for each service shard that has at least one healthy backend endpoint. For example, in us-central1-a, 104.197.247.191 is the external IP address of the service shard in that zone, and in asia-east1-a the address is 130.211.56.221. -2. Similarly, there are regional 'A' records which include all healthy shards in that region. For example, 'us-central1'. These regional records are useful for clients which do not have a particular zone preference, and as a building block for the automated locality and failover mechanism described below. -3. For zones where there are currently no healthy backend endpoints, a CNAME ('Canonical Name') record is used to alias (automatically redirect) those queries to the next closest healthy zone. In the example, the service shard in us-central1-f currently has no healthy backend endpoints (that is Pods), so a CNAME record has been created to automatically redirect queries to other shards in that region (us-central1 in this case). -4. Similarly, if no healthy shards exist in the enclosing region, the search progresses further afield. In the europe-west1-d availability zone, there are no healthy backends, so queries are redirected to the broader europe-west1 region (which also has no healthy backends), and onward to the global set of healthy addresses (' nginx.mynamespace.myfederation.svc.example.com.'). - -The above set of DNS records is automatically kept in sync with the -current state of health of all service shards globally by the -Federated Service system. DNS resolver libraries (which are invoked by -all clients) automatically traverse the hierarchy of 'CNAME' and 'A' -records to return the correct set of healthy IP addresses. Clients can -then select any one of the returned addresses to initiate a network -connection (and fail over automatically to one of the other equivalent -addresses if required). - -## Discovering a federated service - -### From pods inside your federated clusters - -By default, Kubernetes clusters come pre-configured with a -cluster-local DNS server ('KubeDNS'), as well as an intelligently -constructed DNS search path which together ensure that DNS queries -like "myservice", "myservice.mynamespace", -"bobsservice.othernamespace" etc issued by your software running -inside Pods are automatically expanded and resolved correctly to the -appropriate service IP of services running in the local cluster. - -With the introduction of Federated Services and Cross-Cluster Service -Discovery, this concept is extended to cover Kubernetes services -running in any other cluster across your Cluster Federation, globally. -To take advantage of this extended range, you use a slightly different -DNS name of the form ```".."``` -to resolve Federated Services. For example, you might use -`myservice.mynamespace.myfederation`. Using a different DNS name also -avoids having your existing applications accidentally traversing -cross-zone or cross-region networks and you incurring perhaps unwanted -network charges or latency, without you explicitly opting in to this -behavior. - -So, using our NGINX example service above, and the Federated Service -DNS name form just described, let's consider an example: A Pod in a -cluster in the `us-central1-f` availability zone needs to contact our -NGINX service. Rather than use the service's traditional cluster-local -DNS name (`"nginx.mynamespace"`, which is automatically expanded -to `"nginx.mynamespace.svc.cluster.local"`) it can now use the -service's Federated DNS name, which is -`"nginx.mynamespace.myfederation"`. This will be automatically -expanded and resolved to the closest healthy shard of my NGINX -service, wherever in the world that may be. If a healthy shard exists -in the local cluster, that service's cluster-local (typically -10.x.y.z) IP address will be returned (by the cluster-local KubeDNS). -This is almost exactly equivalent to non-federated service resolution -(almost because KubeDNS actually returns both a CNAME and an A record -for local federated services, but applications will be oblivious -to this minor technical difference). - -But if the service does not exist in the local cluster (or it exists -but has no healthy backend pods), the DNS query is automatically -expanded to ```"nginx.mynamespace.myfederation.svc.us-central1-f.example.com"``` -(that is, logically "find the external IP of one of the shards closest to -my availability zone"). This expansion is performed automatically by -KubeDNS, which returns the associated CNAME record. This results in -automatic traversal of the hierarchy of DNS records in the above -example, and ends up at one of the external IPs of the Federated -Service in the local us-central1 region (that is 104.197.247.191, -104.197.244.180 or 104.197.245.170). - -It is of course possible to explicitly target service shards in -availability zones and regions other than the ones local to a Pod by -specifying the appropriate DNS names explicitly, and not relying on -automatic DNS expansion. For example, -"nginx.mynamespace.myfederation.svc.europe-west1.example.com" will -resolve to all of the currently healthy service shards in Europe, even -if the Pod issuing the lookup is located in the U.S., and irrespective -of whether or not there are healthy shards of the service in the U.S. -This is useful for remote monitoring and other similar applications. - -### From other clients outside your federated clusters - -Much of the above discussion applies equally to external clients, -except that the automatic DNS expansion described is no longer -possible. So external clients need to specify one of the fully -qualified DNS names of the Federated Service, be that a zonal, -regional or global name. For convenience reasons, it is often a good -idea to manually configure additional static CNAME records in your -service, for example: - -``` shell -eu.nginx.acme.com CNAME nginx.mynamespace.myfederation.svc.europe-west1.example.com. -us.nginx.acme.com CNAME nginx.mynamespace.myfederation.svc.us-central1.example.com. -nginx.acme.com CNAME nginx.mynamespace.myfederation.svc.example.com. -``` -That way your clients can always use the short form on the left, and -always be automatically routed to the closest healthy shard on their -home continent. All of the required failover is handled for you -automatically by Kubernetes Cluster Federation. Future releases will -improve upon this even further. - -## Handling failures of backend pods and whole clusters - -Standard Kubernetes service cluster-IP's already ensure that -non-responsive individual Pod endpoints are automatically taken out of -service with low latency (a few seconds). In addition, as alluded -above, the Kubernetes Cluster Federation system automatically monitors -the health of clusters and the endpoints behind all of the shards of -your Federated Service, taking shards in and out of service as -required (for example, when all of the endpoints behind a service, or perhaps -the entire cluster or availability zone go down, or conversely recover -from an outage). Due to the latency inherent in DNS caching (the cache -timeout, or TTL for Federated Service DNS records is configured to 3 -minutes, by default, but can be adjusted), it may take up to that long -for all clients to completely fail over to an alternative cluster in -the case of catastrophic failure. However, given the number of -discrete IP addresses which can be returned for each regional service -endpoint (such as us-central1 above, which has three alternatives) -many clients will fail over automatically to one of the alternative -IP's in less time than that given appropriate configuration. - -{{% /capture %}} - -{{% capture discussion %}} - -## Troubleshooting - -### I cannot connect to my cluster federation API -Check that your - -1. Client (typically kubectl) is correctly configured (including API endpoints and login credentials). -2. Cluster Federation API server is running and network-reachable. - -See the [federation admin guide](/docs/admin/federation/) to learn -how to bring up a cluster federation correctly (or have your cluster administrator do this for you), and how to correctly configure your client. - -### I can create a federated service successfully against the cluster federation API, but no matching services are created in my underlying clusters -Check that: - -1. Your clusters are correctly registered in the Cluster Federation API (`kubectl describe clusters`). -2. Your clusters are all 'Active'. This means that the cluster Federation system was able to connect and authenticate against the clusters' endpoints. If not, consult the logs of the federation-controller-manager pod to ascertain what the failure might be. - ``` - kubectl --namespace=federation logs $(kubectl get pods --namespace=federation -l module=federation-controller-manager -o name) - ``` -3. That the login credentials provided to the Cluster Federation API for the clusters have the correct authorization and quota to create services in the relevant namespace in the clusters. Again you should see associated error messages providing more detail in the above log file if this is not the case. -4. Whether any other error is preventing the service creation operation from succeeding (look for `service-controller` errors in the output of `kubectl logs federation-controller-manager --namespace federation`). - -### I can create a federated service successfully, but no matching DNS records are created in my DNS provider. -Check that: - -1. Your federation name, DNS provider, DNS domain name are configured correctly. Consult the [federation admin guide](/docs/admin/federation/) or [tutorial](https://github.com/kelseyhightower/kubernetes-cluster-federation) to learn -how to configure your Cluster Federation system's DNS provider (or have your cluster administrator do this for you). -2. Confirm that the Cluster Federation's service-controller is successfully connecting to and authenticating against your selected DNS provider (look for `service-controller` errors or successes in the output of `kubectl logs federation-controller-manager --namespace federation`). -3. Confirm that the Cluster Federation's service-controller is successfully creating DNS records in your DNS provider (or outputting errors in its logs explaining in more detail what's failing). - -### Matching DNS records are created in my DNS provider, but clients are unable to resolve against those names -Check that: - -1. The DNS registrar that manages your federation DNS domain has been correctly configured to point to your configured DNS provider's nameservers. See for example [Google Domains Documentation](https://support.google.com/domains/answer/3290309?hl=en&ref_topic=3251230) and [Google Cloud DNS Documentation](https://cloud.google.com/dns/update-name-servers), or equivalent guidance from your domain registrar and DNS provider. - -### This troubleshooting guide did not help me solve my problem - -1. Please use one of our [support channels](/docs/tasks/debug-application-cluster/troubleshooting/) to seek assistance. - -## For more information - - * [Federation proposal](https://git.k8s.io/community/contributors/design-proposals/multicluster/federation.md) details use cases that motivated this work. -{{% /capture %}} diff --git a/content/en/docs/tasks/federation/set-up-cluster-federation-kubefed.md b/content/en/docs/tasks/federation/set-up-cluster-federation-kubefed.md deleted file mode 100644 index 4cf0fd49d1..0000000000 --- a/content/en/docs/tasks/federation/set-up-cluster-federation-kubefed.md +++ /dev/null @@ -1,564 +0,0 @@ ---- -title: Set up Cluster Federation with Kubefed -reviewers: -- madhusudancs -content_template: templates/task -weight: 125 ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -Kubernetes version 1.5 and above includes a new command line tool called -[`kubefed`](/docs/admin/kubefed/) to help you administrate your federated -clusters. `kubefed` helps you to deploy a new Kubernetes cluster federation -control plane, and to add clusters to or remove clusters from an existing -federation control plane. - -This guide explains how to administer a Kubernetes Cluster Federation -using `kubefed`. - -> Note: `kubefed` is a beta feature in Kubernetes 1.6. - -{{% /capture %}} - - -{{% capture prerequisites %}} - -{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}} - -{{% /capture %}} - -{{% capture steps %}} - -## Prerequisites - -This guide assumes that you have a running Kubernetes cluster. Please -see one of the [getting started](/docs/setup/) guides -for installation instructions for your platform. - -## Getting `kubefed` - -Download the client tarball corresponding to the particular release and -extract the binaries in the tarball: - -{{< note >}} -Until Kubernetes version `1.8.x` the federation project was -maintained as part of the [core kubernetes repo](https://github.com/kubernetes/kubernetes). -Between Kubernetes releases `1.8` and `1.9`, the federation project moved into -a separate [federation repo](https://github.com/kubernetes/federation), where it is -now maintained. Consequently, the federation release information is available on the -[release page](https://github.com/kubernetes/federation/releases). -{{< /note >}} - -### For Kubernetes versions 1.8.x and earlier: - -```shell -curl -LO https://storage.googleapis.com/kubernetes-release/release/${RELEASE-VERSION}/kubernetes-client-linux-amd64.tar.gz -tar -xzvf kubernetes-client-linux-amd64.tar.gz -``` -{{< note >}} -The `RELEASE-VERSION` variable should either be set to or replaced with the actual version needed. -{{< /note >}} - -Copy the extracted binary to one of the directories in your `$PATH` -and set the executable permission on the binary. - -```shell -sudo cp kubernetes/client/bin/kubefed /usr/local/bin -sudo chmod +x /usr/local/bin/kubefed -``` - -### For Kubernetes versions 1.9.x and above: - -```shell -curl -LO https://storage.cloud.google.com/kubernetes-federation-release/release/${RELEASE-VERSION}/federation-client-linux-amd64.tar.gz -tar -xzvf federation-client-linux-amd64.tar.gz -``` - -{{< note >}} -The `RELEASE-VERSION` variable should be replaced with one of the release versions available at [federation release page](https://github.com/kubernetes/federation/releases). -{{< /note >}} - -Copy the extracted binary to one of the directories in your `$PATH` -and set the executable permission on the binary. - -```shell -sudo cp federation/client/bin/kubefed /usr/local/bin -sudo chmod +x /usr/local/bin/kubefed -``` - -### Install kubectl - -You can install a matching version of kubectl using the instructions on -the [kubectl install page](/docs/tasks/tools/install-kubectl/). - -## Choosing a host cluster. - -You'll need to choose one of your Kubernetes clusters to be the -*host cluster*. The host cluster hosts the components that make up -your federation control plane. Ensure that you have a `kubeconfig` -entry in your local `kubeconfig` that corresponds to the host cluster. -You can verify that you have the required `kubeconfig` entry by -running: - -```shell -kubectl config get-contexts -``` - -The output should contain an entry corresponding to your host cluster, -similar to the following: - -``` -CURRENT NAME CLUSTER AUTHINFO NAMESPACE -* gke_myproject_asia-east1-b_gce-asia-east1 gke_myproject_asia-east1-b_gce-asia-east1 gke_myproject_asia-east1-b_gce-asia-east1 -``` - - -You'll need to provide the `kubeconfig` context (called name in the -entry above) for your host cluster when you deploy your federation -control plane. - - -## Deploying a federation control plane - -To deploy a federation control plane on your host cluster, run -[`kubefed init`](/docs/admin/kubefed_init/) command. When you use -`kubefed init`, you must provide the following: - -* Federation name -* `--host-cluster-context`, the `kubeconfig` context for the host cluster -* `--dns-provider`, one of `'google-clouddns'`, `aws-route53` or `coredns` -* `--dns-zone-name`, a domain name suffix for your federated services - -If your host cluster is running in a non-cloud environment or an -environment that doesn't support common cloud primitives such as -load balancers, you might need additional flags. Please see the -[on-premises host clusters](#on-premises-host-clusters) section below. - -The following example command deploys a federation control plane with -the name `fellowship`, a host cluster context `rivendell`, and the -domain suffix `example.com.`: - -```shell -kubefed init fellowship \ - --host-cluster-context=rivendell \ - --dns-provider="google-clouddns" \ - --dns-zone-name="example.com." -``` - -The domain suffix specified in `--dns-zone-name` must be an existing -domain that you control, and that is programmable by your DNS provider. -It must also end with a trailing dot. - -Once the federation control plane is initialized, query the namespaces: - -```shell -kubectl get namespace --context=fellowship -``` - -If you do not see the `default` namespace listed (this is due to a -[bug](https://github.com/kubernetes/kubernetes/issues/33292)). Create it -yourself with the following command: - -```shell -kubectl create namespace default --context=fellowship -``` - -The machines in your host cluster must have the appropriate permissions -to program the DNS service that you are using. For example, if your -cluster is running on Google Compute Engine, you must enable the -Google Cloud DNS API for your project. - -The machines in Google Kubernetes Engine clusters are created -without the Google Cloud DNS API scope by default. If you want to use a -Google Kubernetes Engine cluster as a Federation host, you must create it using the `gcloud` -command with the appropriate value in the `--scopes` field. You cannot -modify a Google Kubernetes Engine cluster directly to add this scope, but you can create a -new node pool for your cluster and delete the old one. - -{{< note >}} -This will cause pods in the cluster to be rescheduled. -{{< /note >}} - -To add the new node pool, run: - -```shell -scopes="$(gcloud container node-pools describe --cluster=gke-cluster default-pool --format='value[delimiter=","](config.oauthScopes)')" -gcloud container node-pools create new-np \ - --cluster=gke-cluster \ - --scopes="${scopes},https://www.googleapis.com/auth/ndev.clouddns.readwrite" -``` - -To delete the old node pool, run: - -```shell -gcloud container node-pools delete default-pool --cluster gke-cluster -``` - -`kubefed init` sets up the federation control plane in the host -cluster and also adds an entry for the federation API server in your -local kubeconfig. - -{{< note >}} -In the beta release of Kubernetes 1.6, `kubefed init` does not automatically set the current context to the -newly deployed federation. You can set the current context manually by running: - -```shell -kubectl config use-context fellowship -``` - -where `fellowship` is the name of your federation. -{{< /note >}} - -### Basic and token authentication support - -`kubefed init` by default only generates TLS certificates and keys -to authenticate with the federation API server and writes them to -your local kubeconfig file. If you wish to enable basic authentication -or token authentication for debugging purposes, you can enable them by -passing the `--apiserver-enable-basic-auth` flag or the -`--apiserver-enable-token-auth` flag. - -```shell -kubefed init fellowship \ - --host-cluster-context=rivendell \ - --dns-provider="google-clouddns" \ - --dns-zone-name="example.com." \ - --apiserver-enable-basic-auth=true \ - --apiserver-enable-token-auth=true -``` - -### Passing command line arguments to federation components - -`kubefed init` bootstraps a federation control plane with default -arguments to federation API server and federation controller manager. -Some of these arguments are derived from `kubefed init`'s flags. -However, you can override these command line arguments by passing -them via the appropriate override flags. - -You can override the federation API server arguments by passing them -to `--apiserver-arg-overrides` and override the federation controller -manager arguments by passing them to -`--controllermanager-arg-overrides`. - -```shell -kubefed init fellowship \ - --host-cluster-context=rivendell \ - --dns-provider="google-clouddns" \ - --dns-zone-name="example.com." \ - --apiserver-arg-overrides="--anonymous-auth=false,--v=4" \ - --controllermanager-arg-overrides="--controllers=services=false" -``` - -### Configuring a DNS provider - -The Federated service controller programs a DNS provider to expose -federated services via DNS names. Certain cloud providers -automatically provide the configuration required to program the -DNS provider if the host cluster's cloud provider is same as the DNS -provider. In all other cases, you have to provide the DNS provider -configuration to your federation controller manager which will in-turn -be passed to the federated service controller. You can provide this -configuration to federation controller manager by storing it in a file -and passing the file's local filesystem path to `kubefed init`'s -`--dns-provider-config` flag. For example, save the config below in -`$HOME/coredns-provider.conf`. - -```ini -[Global] -etcd-endpoints = http://etcd-cluster.ns:2379 -zones = example.com. -``` - -And then pass this file to `kubefed init`: - -```shell -kubefed init fellowship \ - --host-cluster-context=rivendell \ - --dns-provider="coredns" \ - --dns-zone-name="example.com." \ - --dns-provider-config="$HOME/coredns-provider.conf" -``` - -### On-premises host clusters - -#### API server service type - -`kubefed init` exposes the federation API server as a Kubernetes -[service](/docs/concepts/services-networking/service/) on the host cluster. By default, -this service is exposed as a -[load balanced service](/docs/concepts/services-networking/service/#loadbalancer). -Most on-premises and bare-metal environments, and some cloud -environments lack support for load balanced services. `kubefed init` -allows exposing the federation API server as a -[`NodePort` service](/docs/concepts/services-networking/service/#nodeport) on -such environments. This can be accomplished by passing -the `--api-server-service-type=NodePort` flag. You can also specify -the preferred address to advertise the federation API server by -passing the `--api-server-advertise-address=` -flag. Otherwise, one of the host cluster's node address is chosen as -the default. - -```shell -kubefed init fellowship \ - --host-cluster-context=rivendell \ - --dns-provider="google-clouddns" \ - --dns-zone-name="example.com." \ - --api-server-service-type="NodePort" \ - --api-server-advertise-address="10.0.10.20" -``` - -#### Provisioning storage for etcd - -Federation control plane stores its state in -[`etcd`](https://coreos.com/etcd/docs/latest/). -[`etcd`](https://coreos.com/etcd/docs/latest/) data must be stored in -a persistent storage volume to ensure correct operation across -federation control plane restarts. On host clusters that support -[dynamic provisioning of storage volumes](/docs/concepts/storage/persistent-volumes/#dynamic), -`kubefed init` dynamically provisions a -[`PersistentVolume`](/docs/concepts/storage/persistent-volumes/#persistent-volumes) -and binds it to a -[`PersistentVolumeClaim`](/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims) -to store [`etcd`](https://coreos.com/etcd/docs/latest/) data. If your -host cluster doesn't support dynamic provisioning, you can also -statically provision a -[`PersistentVolume`](/docs/concepts/storage/persistent-volumes/#persistent-volumes). -`kubefed init` creates a -[`PersistentVolumeClaim`](/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims) -that has the following configuration: - -```yaml -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - annotations: - volume.alpha.kubernetes.io/storage-class: "yes" - labels: - app: federated-cluster - name: fellowship-federation-apiserver-etcd-claim - namespace: federation-system -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 10Gi -``` - -To statically provision a -[`PersistentVolume`](/docs/concepts/storage/persistent-volumes/#persistent-volumes), -you must ensure that the -[`PersistentVolume`](/docs/concepts/storage/persistent-volumes/#persistent-volumes) -that you create has the matching storage class, access mode and -at least as much capacity as the requested -[`PersistentVolumeClaim`](/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims). - -Alternatively, you can disable persistent storage completely -by passing `--etcd-persistent-storage=false` to `kubefed init`. -However, we do not recommended this because your federation control -plane cannot survive restarts in this mode. - -```shell -kubefed init fellowship \ - --host-cluster-context=rivendell \ - --dns-provider="google-clouddns" \ - --dns-zone-name="example.com." \ - --etcd-persistent-storage=false -``` - -`kubefed init` still doesn't support attaching an existing -[`PersistentVolumeClaim`](/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims) -to the federation control plane that it bootstraps. We are planning to -support this in a future version of `kubefed`. - -#### CoreDNS support - -Federated services now support [CoreDNS](https://coredns.io/) as one -of the DNS providers. If you are running your clusters and federation -in an environment that does not have access to cloud-based DNS -providers, then you can run your own [CoreDNS](https://coredns.io/) -instance and publish the federated service DNS names to that server. - -You can configure your federation to use -[CoreDNS](https://coredns.io/), by passing appropriate values to -`kubefed init`'s `--dns-provider` and `--dns-provider-config` flags. - -```shell -kubefed init fellowship \ - --host-cluster-context=rivendell \ - --dns-provider="coredns" \ - --dns-zone-name="example.com." \ - --dns-provider-config="$HOME/coredns-provider.conf" -``` - -For more information see -[Setting up CoreDNS as DNS provider for Cluster Federation](/docs/tasks/federation/set-up-coredns-provider-federation/). - -#### AWS Route53 support - -It is possible to utilize AWS Route53 as a cloud DNS provider when the -federation controller-manager is run on-premise. The controller-manager -Deployment must be configured with AWS credentials since it cannot implicitly -gather them from a VM running on AWS. - -Currently, `kubefed init` does not read AWS Route53 credentials from the -`--dns-provider-config` flag, so a patch must be applied. - -Specify AWS Route53 as your DNS provider when initializing your on-premise -federation controller-manager by passing the flag `--dns-provider="aws-route53"` -to `kubefed init`. - -Create a patch file with your AWS credentials: - -```yaml -spec: - template: - spec: - containers: - - name: controller-manager - env: - - name: AWS_ACCESS_KEY_ID - value: "ABCDEFG1234567890" - - name: AWS_SECRET_ACCESS_KEY - value: "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" -``` - -Patch the Deployment: - -```shell -kubectl -n federation-system patch deployment controller-manager --patch "$(cat .yml)" -``` - -Where `` is the name of the file you created above. - -## Adding a cluster to a federation - -After you've deployed a federation control plane, you'll need to make that control plane aware of the clusters it should manage. - -To join clusters into the federation: - -1. Change the context: - - ```shell - kubectl config use-context fellowship - ``` - -1. If you are using a managed cluster service, allow the service to access the cluster. To do this, create a `clusterrolebinding` for the account associated with your cluster service: - - ```shell - kubectl create clusterrolebinding -cluster-admin-binding --clusterrole=cluster-admin --user=@example.org --context= - ``` - -1. Join the cluster to the federation, using `kubefed join`, and make sure you provide the following: - - * The name of the cluster that you are joining to the federation - * `--host-cluster-context`, the kubeconfig context for the host cluster - - For example, this command adds the cluster `gondor` to the federation running on host cluster `rivendell`: - - ```shell - kubefed join gondor --host-cluster-context=rivendell - ``` - -A new context has now been added to your kubeconfig named `fellowship` (after the name of your federation). - - -{{< note >}} -The name that you provide to the `join` command is used as the joining cluster's identity in federation. This name should adhere to the rules described in the [identifiers doc](/docs/concepts/overview/working-with-objects/names/). If the context -corresponding to your joining cluster conforms to these rules, you can use the same name in the join command. Otherwise, you must choose a different name for your cluster's identity. -{{< /note >}} - -### Naming rules and customization - -The cluster name you supply to `kubefed join` must be a valid -[RFC 1035](https://www.ietf.org/rfc/rfc1035.txt) label and are -enumerated in the [Identifiers doc](/docs/concepts/overview/working-with-objects/names/). - -Furthermore, federation control plane requires credentials of the -joined clusters to operate on them. These credentials are obtained -from the local kubeconfig. `kubefed join` uses the cluster name -specified as the argument to look for the cluster's context in the -local kubeconfig. If it fails to find a matching context, it exits -with an error. - -This might cause issues in cases where context names for each cluster -in the federation don't follow -[RFC 1035](https://www.ietf.org/rfc/rfc1035.txt) label naming rules. -In such cases, you can specify a cluster name that conforms to the -[RFC 1035](https://www.ietf.org/rfc/rfc1035.txt) label naming rules -and specify the cluster context using the `--cluster-context` flag. -For example, if context of the cluster you are joining is -`gondor_needs-no_king`, then you can join the cluster by running: - -```shell -kubefed join gondor --host-cluster-context=rivendell --cluster-context=gondor_needs-no_king -``` - -#### Secret name - -Cluster credentials required by the federation control plane as -described above are stored as a secret in the host cluster. The name -of the secret is also derived from the cluster name. - -However, the name of a secret object in Kubernetes should conform -to the DNS subdomain name specification described in -[RFC 1123](https://tools.ietf.org/html/rfc1123). If this isn't the -case, you can pass the secret name to `kubefed join` using the -`--secret-name` flag. For example, if the cluster name is `noldor` and -the secret name is `11kingdom`, you can join the cluster by -running: - -```shell -kubefed join noldor --host-cluster-context=rivendell --secret-name=11kingdom -``` - -{{< note >}} -If your cluster name does not conform to the DNS subdomain name specification, all you need to do is supply the secret name using the `--secret-name` flag. `kubefed join` automatically creates the secret for you. -{{< /note >}} - -### `kube-dns` configuration - -`kube-dns` configuration must be updated in each joining cluster to -enable federated service discovery. If the joining Kubernetes cluster -is version 1.5 or newer and your `kubefed` is version 1.6 or newer, -then this configuration is automatically managed for you when the -clusters are joined or unjoined using `kubefed join` or `unjoin` -commands. - -In all other cases, you must update `kube-dns` configuration manually -as described in the -[Updating KubeDNS section of the admin guide](/docs/admin/federation/). - -## Removing a cluster from a federation - -To remove a cluster from a federation, run the [`kubefed unjoin`](/docs/reference/setup-tools/kubefed/kubefed_unjoin/) -command with the cluster name and the federation's -`--host-cluster-context`: - -```shell -kubefed unjoin gondor --host-cluster-context=rivendell -``` - -## Turning down the federation control plane - -Proper cleanup of federation control plane is not fully implemented in -this beta release of `kubefed`. However, for the time being, deleting -the federation system namespace should remove all the resources except -the persistent storage volume dynamically provisioned for the -federation control plane's etcd. You can delete the federation -namespace by running the following command: - -```shell -kubectl delete ns federation-system --context=rivendell -``` - -{{< note >}} -`rivendell` is the host cluster name. Replace that name with the appropriate name in your configuration. -{{< /note >}} - -{{% /capture %}} diff --git a/content/en/docs/tasks/federation/set-up-coredns-provider-federation.md b/content/en/docs/tasks/federation/set-up-coredns-provider-federation.md deleted file mode 100644 index 572a348a82..0000000000 --- a/content/en/docs/tasks/federation/set-up-coredns-provider-federation.md +++ /dev/null @@ -1,152 +0,0 @@ ---- -title: Set up CoreDNS as DNS provider for Cluster Federation -content_template: templates/tutorial -weight: 130 ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This page shows how to configure and deploy CoreDNS to be used as the -DNS provider for Cluster Federation. - -{{% /capture %}} - - -{{% capture objectives %}} - -* Configure and deploy CoreDNS server -* Bring up federation with CoreDNS as dns provider -* Setup CoreDNS server in nameserver lookup chain - -{{% /capture %}} - - -{{% capture prerequisites %}} - -* You need to have a running Kubernetes cluster (which is -referenced as host cluster). Please see one of the -[getting started](/docs/setup/) guides for -installation instructions for your platform. -* Support for `LoadBalancer` services in member clusters of federation is -mandatory to enable `CoreDNS` for service discovery across federated clusters. - -{{% /capture %}} - - -{{% capture lessoncontent %}} - -## Deploying CoreDNS and etcd charts - -CoreDNS can be deployed in various configurations. Explained below is a -reference and can be tweaked to suit the needs of the platform and the -cluster federation. - -To deploy CoreDNS, we shall make use of helm charts. CoreDNS will be -deployed with [etcd](https://coreos.com/etcd) as the backend and should -be pre-installed. etcd can also be deployed using helm charts. Shown -below are the instructions to deploy etcd. - - helm install --namespace my-namespace --name etcd-operator stable/etcd-operator - helm upgrade --namespace my-namespace --set cluster.enabled=true etcd-operator stable/etcd-operator - -*Note: etcd default deployment configurations can be overridden, suiting the -host cluster.* - -After deployment succeeds, etcd can be accessed with the -[http://etcd-cluster.my-namespace:2379](http://etcd-cluster.my-namespace:2379) endpoint within the host cluster. - -The CoreDNS default configuration should be customized to suit the federation. -Shown below is the Values.yaml, which overrides the default -configuration parameters on the CoreDNS chart. - -```yaml -isClusterService: false -serviceType: "LoadBalancer" -plugins: - kubernetes: - enabled: false - etcd: - enabled: true - zones: - - "example.com." - endpoint: "http://etcd-cluster.my-namespace:2379" -``` - -The above configuration file needs some explanation: - - - `isClusterService` specifies whether CoreDNS should be deployed as a -cluster-service, which is the default. You need to set it to false, so -that CoreDNS is deployed as a Kubernetes application service. - - `serviceType` specifies the type of Kubernetes service to be created -for CoreDNS. You need to choose either "LoadBalancer" or "NodePort" to -make the CoreDNS service accessible outside the Kubernetes cluster. - - Disable `plugins.kubernetes`, which is enabled by default by -setting `plugins.kubernetes.enabled` to false. - - Enable `plugins.etcd` by setting `plugins.etcd.enabled` to -true. - - Configure the DNS zone (federation domain) for which CoreDNS is -authoritative by setting `plugins.etcd.zones` as shown above. - - Configure the etcd endpoint which was deployed earlier by setting -`plugins.etcd.endpoint` - -Now deploy CoreDNS by running - - helm install --namespace my-namespace --name coredns -f Values.yaml stable/coredns - -Verify that both etcd and CoreDNS pods are running as expected. - - -## Deploying Federation with CoreDNS as DNS provider - -The Federation control plane can be deployed using `kubefed init`. CoreDNS -can be chosen as the DNS provider by specifying two additional parameters. - - --dns-provider=coredns - --dns-provider-config=coredns-provider.conf - -coredns-provider.conf has below format: - - [Global] - etcd-endpoints = http://etcd-cluster.my-namespace:2379 - zones = example.com. - coredns-endpoints = : - - - `etcd-endpoints` is the endpoint to access etcd. - - `zones` is the federation domain for which CoreDNS is authoritative and is same as --dns-zone-name flag of `kubefed init`. - - `coredns-endpoints` is the endpoint to access CoreDNS server. This is an optional parameter introduced from v1.7 onwards. - -{{< note >}} -`plugins.etcd.zones` in the CoreDNS configuration and the `--dns-zone-name` flag to `kubefed init` should match. -{{< /note >}} - - -## Setup CoreDNS server in nameserver resolv.conf chain - -{{< note >}} -The following section applies only to versions prior to v1.7 -and will be automatically taken care of if the `coredns-endpoints` -parameter is configured in `coredns-provider.conf` as described in -section above. -{{< /note >}} - -Once the federation control plane is deployed and federated clusters -are joined to the federation, you need to add the CoreDNS server to the -pod's nameserver resolv.conf chain in all the federated clusters as this -self hosted CoreDNS server is not discoverable publicly. This can be -achieved by adding the below line to `dnsmasq` container's arg in -`kube-dns` deployment. - - --server=/example.com./ - -Replace `example.com` above with federation domain. - - -Now the federated cluster is ready for cross-cluster service discovery! - -{{% /capture %}} - - diff --git a/content/en/docs/tasks/federation/set-up-placement-policies-federation.md b/content/en/docs/tasks/federation/set-up-placement-policies-federation.md deleted file mode 100644 index d7ac469ea9..0000000000 --- a/content/en/docs/tasks/federation/set-up-placement-policies-federation.md +++ /dev/null @@ -1,221 +0,0 @@ ---- -title: Set up placement policies in Federation -content_template: templates/task -weight: 135 ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This page shows how to enforce policy-based placement decisions over Federated -resources using an external policy engine. - -{{% /capture %}} - -{{% capture prerequisites %}} - -You need to have a running Kubernetes cluster (which is referenced as host -cluster). Please see one of the [getting started](/docs/setup/) -guides for installation instructions for your platform. - -{{% /capture %}} - -{{% capture steps %}} - -## Deploying Federation and configuring an external policy engine - -The Federation control plane can be deployed using `kubefed init`. - -After deploying the Federation control plane, you must configure an Admission -Controller in the Federation API server that enforces placement decisions -received from the external policy engine. - - kubectl apply -f scheduling-policy-admission.yaml - -Shown below is an example ConfigMap for the Admission Controller: - -{{< codenew file="federation/scheduling-policy-admission.yaml" >}} - -The ConfigMap contains three files: - -* `config.yml` specifies the location of the `SchedulingPolicy` Admission - Controller config file. -* `scheduling-policy-config.yml` specifies the location of the kubeconfig file - required to contact the external policy engine. This file can also include a - `retryBackoff` value that controls the initial retry backoff delay in - milliseconds. -* `opa-kubeconfig` is a standard kubeconfig containing the URL and credentials - needed to contact the external policy engine. - -Edit the Federation API server deployment to enable the `SchedulingPolicy` -Admission Controller. - - kubectl -n federation-system edit deployment federation-apiserver - -Update the Federation API server command line arguments to enable the Admission -Controller and mount the ConfigMap into the container. If there's an existing -`--enable-admission-plugins` flag, append `,SchedulingPolicy` instead of adding -another line. - - --enable-admission-plugins=SchedulingPolicy - --admission-control-config-file=/etc/kubernetes/admission/config.yml - -Add the following volume to the Federation API server pod: - - - name: admission-config - configMap: - name: admission - -Add the following volume mount the Federation API server `apiserver` container: - - volumeMounts: - - name: admission-config - mountPath: /etc/kubernetes/admission - -## Deploying an external policy engine - -The [Open Policy Agent (OPA)](http://openpolicyagent.org) is an open source, -general-purpose policy engine that you can use to enforce policy-based placement -decisions in the Federation control plane. - -Create a Service in the host cluster to contact the external policy engine: - - kubectl apply -f policy-engine-service.yaml - -Shown below is an example Service for OPA. - -{{< codenew file="federation/policy-engine-service.yaml" >}} - -Create a Deployment in the host cluster with the Federation control plane: - - kubectl apply -f policy-engine-deployment.yaml - -Shown below is an example Deployment for OPA. - -{{< codenew file="federation/policy-engine-deployment.yaml" >}} - -## Configuring placement policies via ConfigMaps - -The external policy engine will discover placement policies created in the -`kube-federation-scheduling-policy` namespace in the Federation API server. - -Create the namespace if it does not already exist: - - kubectl --context=federation create namespace kube-federation-scheduling-policy - -Configure a sample policy to test the external policy engine: - -``` -# OPA supports a high-level declarative language named Rego for authoring and -# enforcing policies. For more information on Rego, visit -# http://openpolicyagent.org. - -# Rego policies are namespaced by the "package" directive. -package kubernetes.placement - -# Imports provide aliases for data inside the policy engine. In this case, the -# policy simply refers to "clusters" below. -import data.kubernetes.clusters - -# The "annotations" rule generates a JSON object containing the key -# "federation.kubernetes.io/replica-set-preferences" mapped to . -# The preferences values is generated dynamically by OPA when it evaluates the -# rule. -# -# The SchedulingPolicy Admission Controller running inside the Federation API -# server will merge these annotations into incoming Federated resources. By -# setting replica-set-preferences, we can control the placement of Federated -# ReplicaSets. -# -# Rules are defined to generate JSON values (booleans, strings, objects, etc.) -# When OPA evaluates a rule, it generates a value IF all of the expressions in -# the body evaluate successfully. All rules can be understood intuitively as -# if where is true if AND AND ... -# is true (for some set of data.) -annotations["federation.kubernetes.io/replica-set-preferences"] = preferences { - input.kind = "ReplicaSet" - value = {"clusters": cluster_map, "rebalance": true} - json.marshal(value, preferences) -} - -# This "annotations" rule generates a value for the "federation.alpha.kubernetes.io/cluster-selector" -# annotation. -# -# In English, the policy asserts that resources in the "production" namespace -# that are not annotated with "criticality=low" MUST be placed on clusters -# labelled with "on-premises=true". -annotations["federation.alpha.kubernetes.io/cluster-selector"] = selector { - input.metadata.namespace = "production" - not input.metadata.annotations.criticality = "low" - json.marshal([{ - "operator": "=", - "key": "on-premises", - "values": "[true]", - }], selector) -} - -# Generates a set of cluster names that satisfy the incoming Federated -# ReplicaSet's requirements. In this case, just PCI compliance. -replica_set_clusters[cluster_name] { - clusters[cluster_name] - not insufficient_pci[cluster_name] -} - -# Generates a set of clusters that must not be used for Federated ReplicaSets -# that request PCI compliance. -insufficient_pci[cluster_name] { - clusters[cluster_name] - input.metadata.annotations["requires-pci"] = "true" - not pci_clusters[cluster_name] -} - -# Generates a set of clusters that are PCI certified. In this case, we assume -# clusters are annotated to indicate if they have passed PCI compliance audits. -pci_clusters[cluster_name] { - clusters[cluster_name].metadata.annotations["pci-certified"] = "true" -} - -# Helper rule to generate a mapping of desired clusters to weights. In this -# case, weights are static. -cluster_map[cluster_name] = {"weight": 1} { - replica_set_clusters[cluster_name] -} -``` - -Shown below is the command to create the sample policy: - - kubectl --context=federation -n kube-federation-scheduling-policy create configmap scheduling-policy --from-file=policy.rego - -This sample policy illustrates a few key ideas: - -* Placement policies can refer to any field in Federated resources. -* Placement policies can leverage external context (for example, Cluster - metadata) to make decisions. -* Administrative policy can be managed centrally. -* Policies can define simple interfaces (such as the `requires-pci` annotation) to - avoid duplicating logic in manifests. - -## Testing placement policies - -Annotate one of the clusters to indicate that it is PCI certified. - - kubectl --context=federation annotate clusters cluster-name-1 pci-certified=true - -Deploy a Federated ReplicaSet to test the placement policy. - -{{< codenew file="federation/replicaset-example-policy.yaml" >}} - -Shown below is the command to deploy a ReplicaSet that *does* match the policy. - - kubectl --context=federation create -f replicaset-example-policy.yaml - -Inspect the ReplicaSet to confirm the appropriate annotations have been applied: - - kubectl --context=federation get rs nginx-pci -o jsonpath='{.metadata.annotations}' - -{{% /capture %}} - - From ceccbc049c6dbbc82df3e16e648c617727407a9b Mon Sep 17 00:00:00 2001 From: Qiming Teng Date: Thu, 20 Feb 2020 07:44:30 +0800 Subject: [PATCH 058/111] Resource name constraints (1) (#19106) xref: #17969, #19099, #18746 --- .../overview/working-with-objects/names.md | 34 +++++++++++++++++-- .../extensible-admission-controllers.md | 2 ++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/content/en/docs/concepts/overview/working-with-objects/names.md b/content/en/docs/concepts/overview/working-with-objects/names.md index af24d5f184..60c07391a5 100644 --- a/content/en/docs/concepts/overview/working-with-objects/names.md +++ b/content/en/docs/concepts/overview/working-with-objects/names.md @@ -2,7 +2,7 @@ reviewers: - mikedanese - thockin -title: Names +title: Object Names and IDs content_template: templates/concept weight: 20 --- @@ -18,14 +18,41 @@ For non-unique user-provided attributes, Kubernetes provides [labels](/docs/conc {{% /capture %}} - {{% capture body %}} ## Names {{< glossary_definition term_id="name" length="all" >}} -Kubernetes resources can have names up to 253 characters long. The characters allowed in names are: digits (0-9), lower case letters (a-z), `-`, and `.`. +Below are three types of commonly used name constraints for resources. + +### DNS Subdomain Names + +Most resource types require a name that can be used as a DNS subdomain name +as defined in [RFC 1123](https://tools.ietf.org/html/rfc1123). +This means the name must: + +- contain no more than 253 characters +- contain only lowercase alphanumeric characters, '-' or '.' +- start with an alphanumeric character +- end with an alphanumeric character + +### DNS Label Names + +Some resource types require their names to follow the DNS +label standard as defined in [RFC 1123](https://tools.ietf.org/html/rfc1123). +This means the name must: + +- contain at most 63 characters +- contain only lowercase alphanumeric characters or '-' +- start with an alphanumeric character +- end with an alphanumeric character + +### Path Segment Names + +Some resource types require their names to be able to be safely encoded as a +path segment. In other words, the name may not be "." or ".." and the name may +not contain "/" or "%". Here’s an example manifest for a Pod named `nginx-demo`. @@ -42,6 +69,7 @@ spec: - containerPort: 80 ``` + {{< note >}} Some resource types have additional restrictions on their names. {{< /note >}} diff --git a/content/en/docs/reference/access-authn-authz/extensible-admission-controllers.md b/content/en/docs/reference/access-authn-authz/extensible-admission-controllers.md index 3500ed0c53..4131a79df8 100644 --- a/content/en/docs/reference/access-authn-authz/extensible-admission-controllers.md +++ b/content/en/docs/reference/access-authn-authz/extensible-admission-controllers.md @@ -631,6 +631,8 @@ So a webhook response to add that label would be: ## Webhook configuration To register admission webhooks, create `MutatingWebhookConfiguration` or `ValidatingWebhookConfiguration` API objects. +The name of a `MutatingWebhookConfiguration` or a `ValidatingWebhookConfiguration` object must be a valid +[DNS subdomain name](/docs/concepts/overview/working-with-objects/names#dns-subdomain-names). Each configuration can contain one or more webhooks. If multiple webhooks are specified in a single configuration, each should be given a unique name. From f24680eab59cefe12da7aacd640692ae47def5a5 Mon Sep 17 00:00:00 2001 From: Jacky Wu Date: Thu, 20 Feb 2020 09:15:03 +0800 Subject: [PATCH 059/111] doc: remove tasks federation index from tasks main page. (#19205) --- content/en/docs/tasks/_index.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/content/en/docs/tasks/_index.md b/content/en/docs/tasks/_index.md index a9298a3329..1dee1f38f1 100644 --- a/content/en/docs/tasks/_index.md +++ b/content/en/docs/tasks/_index.md @@ -57,10 +57,6 @@ Configure your application to trust and use the cluster root Certificate Authori Learn common tasks for administering a cluster. -## Administering Federation - -Configure components in a cluster federation. - ## Managing Stateful Applications Perform common tasks for managing Stateful applications, including scaling, deleting, and debugging StatefulSets. From 21cbf8ea91a1c2c869e41785662e81a2bf9848df Mon Sep 17 00:00:00 2001 From: Kohei Toyoda Date: Thu, 20 Feb 2020 21:37:04 +0900 Subject: [PATCH 060/111] Update output of creating replicaset in controllers/replicaset (#19088) --- .../workloads/controllers/replicaset.md | 82 +++++++++---------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/content/en/docs/concepts/workloads/controllers/replicaset.md b/content/en/docs/concepts/workloads/controllers/replicaset.md index 7077bd5ad3..42451f0089 100644 --- a/content/en/docs/concepts/workloads/controllers/replicaset.md +++ b/content/en/docs/concepts/workloads/controllers/replicaset.md @@ -75,53 +75,50 @@ kubectl describe rs/frontend And you will see output similar to: ```shell -Name: frontend -Namespace: default -Selector: tier=frontend -Labels: app=guestbook - tier=frontend -Annotations: -Replicas: 3 current / 3 desired -Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed +Name: frontend +Namespace: default +Selector: tier=frontend +Labels: app=guestbook + tier=frontend +Annotations: kubectl.kubernetes.io/last-applied-configuration: + {"apiVersion":"apps/v1","kind":"ReplicaSet","metadata":{"annotations":{},"labels":{"app":"guestbook","tier":"frontend"},"name":"frontend",... +Replicas: 3 current / 3 desired +Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed Pod Template: - Labels: app=guestbook - tier=frontend + Labels: tier=frontend Containers: php-redis: - Image: gcr.io/google_samples/gb-frontend:v3 - Port: 80/TCP - Requests: - cpu: 100m - memory: 100Mi - Environment: - GET_HOSTS_FROM: dns - Mounts: - Volumes: + Image: gcr.io/google_samples/gb-frontend:v3 + Port: + Host Port: + Environment: + Mounts: + Volumes: Events: - FirstSeen LastSeen Count From SubobjectPath Type Reason Message - --------- -------- ----- ---- ------------- -------- ------ ------- - 1m 1m 1 {replicaset-controller } Normal SuccessfulCreate Created pod: frontend-qhloh - 1m 1m 1 {replicaset-controller } Normal SuccessfulCreate Created pod: frontend-dnjpy - 1m 1m 1 {replicaset-controller } Normal SuccessfulCreate Created pod: frontend-9si5l + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal SuccessfulCreate 117s replicaset-controller Created pod: frontend-wtsmm + Normal SuccessfulCreate 116s replicaset-controller Created pod: frontend-b2zdv + Normal SuccessfulCreate 116s replicaset-controller Created pod: frontend-vcmts ``` And lastly you can check for the Pods brought up: ```shell -kubectl get Pods +kubectl get pods ``` You should see Pod information similar to: ```shell -NAME READY STATUS RESTARTS AGE -frontend-9si5l 1/1 Running 0 1m -frontend-dnjpy 1/1 Running 0 1m -frontend-qhloh 1/1 Running 0 1m +NAME READY STATUS RESTARTS AGE +frontend-b2zdv 1/1 Running 0 6m36s +frontend-vcmts 1/1 Running 0 6m36s +frontend-wtsmm 1/1 Running 0 6m36s ``` You can also verify that the owner reference of these pods is set to the frontend ReplicaSet. To do this, get the yaml of one of the Pods running: ```shell -kubectl get pods frontend-9si5l -o yaml +kubectl get pods frontend-b2zdv -o yaml ``` The output will look similar to this, with the frontend ReplicaSet's info set in the metadata's ownerReferences field: @@ -129,11 +126,11 @@ The output will look similar to this, with the frontend ReplicaSet's info set in apiVersion: v1 kind: Pod metadata: - creationTimestamp: 2019-01-31T17:20:41Z + creationTimestamp: "2020-02-12T07:06:16Z" generateName: frontend- labels: tier: frontend - name: frontend-9si5l + name: frontend-b2zdv namespace: default ownerReferences: - apiVersion: apps/v1 @@ -141,7 +138,7 @@ metadata: controller: true kind: ReplicaSet name: frontend - uid: 892a2330-257c-11e9-aecd-025000000001 + uid: f391f6db-bb9b-4c09-ae74-6a1f77f3d5cf ... ``` @@ -170,16 +167,17 @@ its desired count. Fetching the Pods: ```shell -kubectl get Pods +kubectl get pods ``` The output shows that the new Pods are either already terminated, or in the process of being terminated: ```shell NAME READY STATUS RESTARTS AGE -frontend-9si5l 1/1 Running 0 1m -frontend-dnjpy 1/1 Running 0 1m -frontend-qhloh 1/1 Running 0 1m -pod2 0/1 Terminating 0 4s +frontend-b2zdv 1/1 Running 0 10m +frontend-vcmts 1/1 Running 0 10m +frontend-wtsmm 1/1 Running 0 10m +pod1 0/1 Terminating 0 1s +pod2 0/1 Terminating 0 1s ``` If you create the Pods first: @@ -195,15 +193,15 @@ kubectl apply -f https://kubernetes.io/examples/controllers/frontend.yaml You shall see that the ReplicaSet has acquired the Pods and has only created new ones according to its spec until the number of its new Pods and the original matches its desired count. As fetching the Pods: ```shell -kubectl get Pods +kubectl get pods ``` Will reveal in its output: ```shell NAME READY STATUS RESTARTS AGE -frontend-pxj4r 1/1 Running 0 5s -pod1 1/1 Running 0 13s -pod2 1/1 Running 0 13s +frontend-hmmj2 1/1 Running 0 9s +pod1 1/1 Running 0 36s +pod2 1/1 Running 0 36s ``` In this manner, a ReplicaSet can own a non-homogenous set of Pods From ec7a6de75231bb29abb799a49249cb7308947db2 Mon Sep 17 00:00:00 2001 From: Ihor Sychevskyi <26163841+Arhell@users.noreply.github.com> Date: Thu, 20 Feb 2020 17:45:07 +0200 Subject: [PATCH 061/111] Fix Invalid link in readme (en) (#19204) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fc0bccb0b9..8be2ae4249 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ The recommended way to run the Kubernetes website locally is to run a specialize > If you are running on Windows, you'll need a few more tools which you can install with [Chocolatey](https://chocolatey.org). `choco install make` -> If you'd prefer to run the website locally without Docker, see [Running the website locally using Hugo](#running-the-site-locally-using-hugo) below. +> If you'd prefer to run the website locally without Docker, see [Running the website locally using Hugo](#running-the-website-locally-using-hugo) below. If you have Docker [up and running](https://www.docker.com/get-started), build the `kubernetes-hugo` Docker image locally: From fef685e16199566b4b75863db2ce6752ba980cdb Mon Sep 17 00:00:00 2001 From: Dan POP Date: Thu, 20 Feb 2020 11:45:57 -0800 Subject: [PATCH 062/111] Added 'ClaimRef' to make documentation clearer (#17914) * added final period (.) * removed backticks Co-authored-by: Leonardo Di Donato Signed-off-by: Dan POP Co-authored-by: Leo Di Donato --- content/en/docs/concepts/storage/persistent-volumes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/concepts/storage/persistent-volumes.md b/content/en/docs/concepts/storage/persistent-volumes.md index 8346fc562c..c59cb2ee3c 100644 --- a/content/en/docs/concepts/storage/persistent-volumes.md +++ b/content/en/docs/concepts/storage/persistent-volumes.md @@ -71,7 +71,7 @@ check [kube-apiserver](/docs/admin/kube-apiserver/) documentation. ### Binding -A user creates, or in the case of dynamic provisioning, has already created, a `PersistentVolumeClaim` with a specific amount of storage requested and with certain access modes. A control loop in the master watches for new PVCs, finds a matching PV (if possible), and binds them together. If a PV was dynamically provisioned for a new PVC, the loop will always bind that PV to the PVC. Otherwise, the user will always get at least what they asked for, but the volume may be in excess of what was requested. Once bound, `PersistentVolumeClaim` binds are exclusive, regardless of how they were bound. A PVC to PV binding is a one-to-one mapping. +A user creates, or in the case of dynamic provisioning, has already created, a PersistentVolumeClaim with a specific amount of storage requested and with certain access modes. A control loop in the master watches for new PVCs, finds a matching PV (if possible), and binds them together. If a PV was dynamically provisioned for a new PVC, the loop will always bind that PV to the PVC. Otherwise, the user will always get at least what they asked for, but the volume may be in excess of what was requested. Once bound, PersistentVolumeClaim binds are exclusive, regardless of how they were bound. A PVC to PV binding is a one-to-one mapping, using a ClaimRef which is a bi-directional binding between the PersistentVolume and the PersistentVolumeClaim. Claims will remain unbound indefinitely if a matching volume does not exist. Claims will be bound as matching volumes become available. For example, a cluster provisioned with many 50Gi PVs would not match a PVC requesting 100Gi. The PVC can be bound when a 100Gi PV is added to the cluster. From bad124b857a2927b75be739646244aacc5190580 Mon Sep 17 00:00:00 2001 From: Fabian Baumanis Date: Thu, 20 Feb 2020 21:41:58 +0100 Subject: [PATCH 063/111] Change back cronjob timezone note to UTC (#18715) --- content/en/docs/concepts/workloads/controllers/cron-jobs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/concepts/workloads/controllers/cron-jobs.md b/content/en/docs/concepts/workloads/controllers/cron-jobs.md index 13b304b120..24492cd18c 100644 --- a/content/en/docs/concepts/workloads/controllers/cron-jobs.md +++ b/content/en/docs/concepts/workloads/controllers/cron-jobs.md @@ -18,7 +18,7 @@ One CronJob object is like one line of a _crontab_ (cron table) file. It runs a on a given schedule, written in [Cron](https://en.wikipedia.org/wiki/Cron) format. {{< note >}} -All **CronJob** `schedule:` times are based on the timezone of the master where the job is initiated. +All **CronJob** `schedule:` times are denoted in UTC. {{< /note >}} When creating the manifest for a CronJob resource, make sure the name you provide From cdf62784aa5804ab63f29564826b81daba245b27 Mon Sep 17 00:00:00 2001 From: Xiaokang An Date: Fri, 21 Feb 2020 15:20:32 +0800 Subject: [PATCH 064/111] Fix ambiguous translation in kubeadm.md (#19201) --- content/zh/docs/reference/setup-tools/kubeadm/kubeadm.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/zh/docs/reference/setup-tools/kubeadm/kubeadm.md b/content/zh/docs/reference/setup-tools/kubeadm/kubeadm.md index 5e338b7039..1d6b42f446 100644 --- a/content/zh/docs/reference/setup-tools/kubeadm/kubeadm.md +++ b/content/zh/docs/reference/setup-tools/kubeadm/kubeadm.md @@ -25,8 +25,8 @@ kubeadm 通过执行必要的操作来启动和运行一个最小可用的集群 * [kubeadm config](/docs/reference/setup-tools/kubeadm/kubeadm-config) 如果你使用 kubeadm v1.7.x 或者更低版本,你需要对你的集群做一些配置以便使用 `kubeadm upgrade` 命令 * [kubeadm token](/docs/reference/setup-tools/kubeadm/kubeadm-token) 使用 `kubeadm join` 来管理令牌 - -* [kubeadm reset](/docs/reference/setup-tools/kubeadm/kubeadm-reset) 使用 `kubeadm init` 或者 `kubeadm join` 来恢复对节点的改变 + +* [kubeadm reset](/docs/reference/setup-tools/kubeadm/kubeadm-reset) 还原之前使用 `kubeadm init` 或者 `kubeadm join` 对节点产生的改变 * [kubeadm version](/docs/reference/setup-tools/kubeadm/kubeadm-version) 打印出 kubeadm 版本 From 499afe4e80211c2997716bd6f739cb3aca467cf2 Mon Sep 17 00:00:00 2001 From: Jamario Rankins Date: Fri, 21 Feb 2020 23:38:47 -0600 Subject: [PATCH 065/111] Fix typo about watch bookmarks (#18902) --- content/en/docs/reference/using-api/api-concepts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/reference/using-api/api-concepts.md b/content/en/docs/reference/using-api/api-concepts.md index e30de75330..776715c8a2 100644 --- a/content/en/docs/reference/using-api/api-concepts.md +++ b/content/en/docs/reference/using-api/api-concepts.md @@ -89,7 +89,7 @@ A given Kubernetes server will only preserve a historical list of changes for a ### Watch bookmarks -To mitigate the impact of short history window, we introduced a concept of `bookmark` watch event. It is a special kind of event to pass an information that all changes up to a given `resourceVersion` client is requesting has already been send. Object returned in that event is of the type requested by the request, but only `resourceVersion` field is set, e.g.: +To mitigate the impact of short history window, we introduced a concept of `bookmark` watch event. It is a special kind of event to pass an information that all changes up to a given `resourceVersion` client is requesting has already been sent. Object returned in that event is of the type requested by the request, but only `resourceVersion` field is set, e.g.: GET /api/v1/namespaces/test/pods?watch=1&resourceVersion=10245&allowWatchBookmarks=true --- From 538dc610d1f9b5885c2938069722ffb65c19714a Mon Sep 17 00:00:00 2001 From: Kirk Larkin <6025110+serpent5@users.noreply.github.com> Date: Sat, 22 Feb 2020 05:40:47 +0000 Subject: [PATCH 066/111] Fix link to nginx + TLS (#19234) --- content/en/docs/concepts/services-networking/ingress.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/concepts/services-networking/ingress.md b/content/en/docs/concepts/services-networking/ingress.md index e916e774c4..6739cf1bd0 100644 --- a/content/en/docs/concepts/services-networking/ingress.md +++ b/content/en/docs/concepts/services-networking/ingress.md @@ -336,7 +336,7 @@ spec: {{< note >}} There is a gap between TLS features supported by various Ingress controllers. Please refer to documentation on -[nginx](https://git.k8s.io/ingress-nginx/README.md#https), +[nginx](https://kubernetes.github.io/ingress-nginx/user-guide/tls/), [GCE](https://git.k8s.io/ingress-gce/README.md#frontend-https), or any other platform specific Ingress controller to understand how TLS works in your environment. {{< /note >}} From 8a03cd1a0a88928234b8708a8c63276a56191576 Mon Sep 17 00:00:00 2001 From: Ihor Sychevskyi <26163841+Arhell@users.noreply.github.com> Date: Sat, 22 Feb 2020 07:46:47 +0200 Subject: [PATCH 067/111] Fix anchor in readme (es) (#19219) --- README-es.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README-es.md b/README-es.md index 15bf9ed2fb..fe71a0fc40 100644 --- a/README-es.md +++ b/README-es.md @@ -28,7 +28,7 @@ El método recomendado para levantar una copia local del sitio web kubernetes.io > Para Windows, algunas otras herramientas como Make son necesarias. Puede instalarlas utilizando el gestor [Chocolatey](https://chocolatey.org). `choco install make` o siguiendo las instrucciones de [Make for Windows](http://gnuwin32.sourceforge.net/packages/make.htm). -> Si prefiere levantar el sitio web sin utilizar **Docker**, puede seguir las instrucciones disponibles en la sección [Levantando kubernetes.io en local con Hugo](#levantando-kubernetes.io-en-local-con-hugo). +> Si prefiere levantar el sitio web sin utilizar **Docker**, puede seguir las instrucciones disponibles en la sección [Levantando kubernetes.io en local con Hugo](#levantando-kubernetesio-en-local-con-hugo). Una vez tenga Docker [configurado en su máquina](https://www.docker.com/get-started), puede construir la imagen de Docker `kubernetes-hugo` localmente ejecutando el siguiente comando en la raíz del repositorio: From 60e4ae412b9b5772ffa1af9dc06540fd65dd8d0a Mon Sep 17 00:00:00 2001 From: GoodGameZoo Date: Sun, 23 Feb 2020 08:58:47 +0800 Subject: [PATCH 068/111] node specific volume limits modification (#19254) --- content/zh/docs/concepts/storage/storage-limits.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/zh/docs/concepts/storage/storage-limits.md b/content/zh/docs/concepts/storage/storage-limits.md index f4db62a082..7b5f8e63be 100644 --- a/content/zh/docs/concepts/storage/storage-limits.md +++ b/content/zh/docs/concepts/storage/storage-limits.md @@ -25,7 +25,7 @@ how many volumes can be attached to a Node. It is important for Kubernetes to respect those limits. Otherwise, Pods scheduled on a Node could get stuck waiting for volumes to attach. --> -谷歌、亚马逊和微软等云供应商通常对可以关联到节点的卷数量进行限制。 +谷歌、亚马逊和微软等云供应商通常对可以关联到节点的卷数量进行限制。 Kubernetes 需要尊重这些限制。 否则,在节点上调度的 Pod 可能会卡住去等待卷的关联。 @@ -135,7 +135,7 @@ Refer to the [CSI specifications](https://github.com/container-storage-interface * 在 Google Compute Engine环境中, -[根据节点类型](https://cloud.google.com/compute/docs/disks/#pdnumberlimits)最多可以将128个卷关联到节点。 +[根据节点类型](https://cloud.google.com/compute/docs/disks/#pdnumberlimits)最多可以将127个卷关联到节点。 * 对于 M5、C5、R5、T3 和 Z1D 类型实例的 Amazon EBS 磁盘,Kubernetes 仅允许 25 个卷关联到节点。 对于 ec2 上的其他实例类型 From 2d774cbb42c4814f9cdc64e61647c047eae19a7c Mon Sep 17 00:00:00 2001 From: GoodGameZoo Date: Sun, 23 Feb 2020 14:28:47 +0800 Subject: [PATCH 069/111] Phrase modification (#19251) --- content/zh/docs/concepts/storage/volume-snapshots.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/zh/docs/concepts/storage/volume-snapshots.md b/content/zh/docs/concepts/storage/volume-snapshots.md index b3ed35292a..3f3a6ad65b 100644 --- a/content/zh/docs/concepts/storage/volume-snapshots.md +++ b/content/zh/docs/concepts/storage/volume-snapshots.md @@ -141,7 +141,7 @@ While a snapshot is being taken of a PersistentVolumeClaim, that PersistentVolum --> 如果一个 PVC 正在被快照用来作为源进行快照创建,则该 PVC 是使用中的。如果用户删除正作为快照源的 PVC API 对象,则 PVC 对象不会立即被删除掉。相反,PVC 对象的删除将推迟到任何快照不在主动使用它为止。当快照的 `Status` 中的 `ReadyToUse`值为 `true` 时,PVC 将不再用作快照源。 -当从 `PersistentVolumeClaim` 中生成快照时,`PersistentVolumeClaim` 就在被使用了。如果删除一个作为快照源的 `PersistentVolumeClaim` 对象,这个 `PersistentVolumeClaim` 对象不会立即被删除的。相反,在快照可以被使用或者被放弃之后,才会执行删除 `PersistentVolumeClaim` 对象的动作。 +当从 `PersistentVolumeClaim` 中生成快照时,`PersistentVolumeClaim` 就在被使用了。如果删除一个作为快照源的 `PersistentVolumeClaim` 对象,这个 `PersistentVolumeClaim` 对象不会立即被删除的。相反,删除 `PersistentVolumeClaim` 对象的动作会被放弃,或者推迟到快照的 Status 为 ReadyToUse时再执行。 要启用动态供应功能,集群管理员需要为用户预先创建一个或多个 `StorageClass` 对象。 -`StorageClass` 对象定义在进行动态卷供应时应使用哪个卷供应商,以及应该将哪些参数传递给该供应商。 -以下清单创建了一个存储类 "slow",它提供类似标准磁盘的永久磁盘。 +`StorageClass` 对象定义当动态供应被调用时,哪一个驱动将被使用和哪些参数将被传递给驱动。 +以下清单创建了一个 `StorageClass` 存储类 "slow",它提供类似标准磁盘的永久磁盘。 ```yaml apiVersion: storage.k8s.io/v1 From f853ee7c73857821a399630641260db70e5dfab1 Mon Sep 17 00:00:00 2001 From: Tim Bannister Date: Sun, 23 Feb 2020 15:00:47 +0000 Subject: [PATCH 073/111] fr translation for project slogan (#18267) * fr translation for project slogan * Update fr homepage abstract --- config.toml | 2 +- content/fr/_index.html | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config.toml b/config.toml index 894eac25ea..c9952bac23 100644 --- a/config.toml +++ b/config.toml @@ -174,7 +174,7 @@ language_alternatives = ["en"] [languages.fr] title = "Kubernetes" -description = "Production-Grade Container Orchestration" +description = "Solution professionnelle d’orchestration de conteneurs" languageName ="Français" weight = 5 contentDir = "content/fr" diff --git a/content/fr/_index.html b/content/fr/_index.html index 7f15e44629..026a0f910f 100644 --- a/content/fr/_index.html +++ b/content/fr/_index.html @@ -1,6 +1,6 @@ --- -title: "La meilleure solution d'orchestration de conteneurs en production" -abstract: "Déploiement, mise à l'échelle et gestion automatisés des conteneurs" +title: "Solution professionnelle d’orchestration de conteneurs" +abstract: "Déploiement, mise à l'échelle et gestion automatisée des conteneurs" cid: home --- From 66a5a05efec36607191a2ee45ff6c3ec770145d0 Mon Sep 17 00:00:00 2001 From: Tim Bannister Date: Sun, 23 Feb 2020 22:24:47 +0000 Subject: [PATCH 074/111] es translation for project slogan (#18260) --- config.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.toml b/config.toml index c9952bac23..50852699a3 100644 --- a/config.toml +++ b/config.toml @@ -222,7 +222,7 @@ language_alternatives = ["en"] [languages.es] title = "Kubernetes" -description = "Production-Grade Container Orchestration" +description = "Orquestación de contenedores para producción" languageName ="Español" weight = 9 contentDir = "content/es" From efa57986d63545919b83cc6cd1a49455748e4978 Mon Sep 17 00:00:00 2001 From: Eli Arbel Date: Mon, 24 Feb 2020 03:10:47 +0200 Subject: [PATCH 075/111] Specify SHA syntax for images (#18774) * Specify SHA syntax * PR suggestion * PR suggestion * Update overview.md * Update content/en/docs/concepts/configuration/overview.md Co-Authored-By: Tim Bannister Co-authored-by: Tim Bannister --- content/en/docs/concepts/configuration/overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/concepts/configuration/overview.md b/content/en/docs/concepts/configuration/overview.md index ca56089b01..100d04ae78 100644 --- a/content/en/docs/concepts/configuration/overview.md +++ b/content/en/docs/concepts/configuration/overview.md @@ -87,7 +87,7 @@ The [imagePullPolicy](/docs/concepts/containers/images/#updating-images) and the - `imagePullPolicy: Never`: the image is assumed to exist locally. No attempt is made to pull the image. {{< note >}} -To make sure the container always uses the same version of the image, you can specify its [digest](https://docs.docker.com/engine/reference/commandline/pull/#pull-an-image-by-digest-immutable-identifier), for example `sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2`. The digest uniquely identifies a specific version of the image, so it is never updated by Kubernetes unless you change the digest value. +To make sure the container always uses the same version of the image, you can specify its [digest](https://docs.docker.com/engine/reference/commandline/pull/#pull-an-image-by-digest-immutable-identifier); replace `:` with `@` (for example, `image@sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2`). The digest uniquely identifies a specific version of the image, so it is never updated by Kubernetes unless you change the digest value. {{< /note >}} {{< note >}} From 393dfe78c970660838120df86436920dd0ebad38 Mon Sep 17 00:00:00 2001 From: Yudi A Phanama <11147376+phanama@users.noreply.github.com> Date: Mon, 24 Feb 2020 09:58:47 +0700 Subject: [PATCH 076/111] Pod Overhead page Indonesian translation (#19249) * Pod Overhead Translation indonesia language * Review+fix id/pod_overhead page translation Co-authored-by: Yudi A Phanama Co-authored-by: sulaimantok Signed-off-by: Yudi A Phanama Co-authored-by: Sulaiman --- .../concepts/configuration/pod-overhead.md | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 content/id/docs/concepts/configuration/pod-overhead.md diff --git a/content/id/docs/concepts/configuration/pod-overhead.md b/content/id/docs/concepts/configuration/pod-overhead.md new file mode 100644 index 0000000000..3c661e4bd5 --- /dev/null +++ b/content/id/docs/concepts/configuration/pod-overhead.md @@ -0,0 +1,54 @@ +--- +title: Overhead Pod +content_template: templates/concept +weight: 20 +--- + +{{% capture overview %}} + +{{< feature-state for_k8s_version="v1.16" state="alpha" >}} + + +Ketika kamu menjalankan Pod pada Node, Pod itu akan mengambil sejumlah sumber daya sistem. Sumber daya ini adalah tambahan terhadap sumber daya yang diperlukan untuk menjalankan Container di dalam Pod (_overhead_). +_Pod Overhead_ adalah fitur yang berfungsi untuk menghitung sumber daya digunakan oleh infrastruktur Pod selain permintaan dan limit Container. + + +{{% /capture %}} + + +{{% capture body %}} + +## Overhead Pod + +Pada Kubernetes, Overhead Pod ditentukan pada +[saat admisi](/docs/reference/access-authn-authz/extensible-admission-controllers/#what-are-admission-webhooks) sesuai dengan Overhead yang ditentukan di dalam +[RuntimeClass](/docs/concepts/containers/runtime-class/) milik Pod. + +Ketika Overhead Pod diaktifkan, Overhead akan dipertimbangkan sebagai tambahan terhadap jumlah permintaan sumber daya Container +saat menjadwalkan Pod. Begitu pula Kubelet, yang akan memasukkan Overhead Pod saat menentukan ukuran +cgroup milik Pod, dan saat melakukan pemeringkatan pengusiran (_eviction_) Pod. + +### Yang perlu disiapkan + +Kamu harus memastikan bahwa +[_feature gate_](/docs/reference/command-line-tools-reference/feature-gates/) `PodOverhead` telah diaktifkan (secara bawaan dinonaktifkan) +di seluruh klaster kamu, yang berarti: + +- Pada {{< glossary_tooltip text="kube-scheduler" term_id="kube-scheduler" >}} +- Pada {{< glossary_tooltip text="kube-apiserver" term_id="kube-apiserver" >}} +- Pada {{< glossary_tooltip text="kubelet" term_id="kubelet" >}} di setiap Node +- Pada peladen API khusus (_custom_) apa pun yang menggunakan _feature gate_ + +{{< note >}} +Pengguna yang dapat mengubah sumber daya RuntimeClass dapat memengaruhi kinerja beban kerja klaster secara keseluruhan. Kamu dapat membatasi akses terhadap kemampuan ini dengan kontrol akses Kubernetes. +Lihat [Ringkasan Otorisasi](/docs/reference/access-authn-authz/authorization/) untuk lebih lanjut. +{{< /note >}} + +{{% /capture %}} + +{{% capture whatsnext %}} + +* [RuntimeClass](/docs/concepts/containers/runtime-class/) +* [Desain PodOverhead](https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/20190226-pod-overhead.md) + +{{% /capture %}} From 7a97b21f2682bf13d37ae0816ac667f11aa6ab36 Mon Sep 17 00:00:00 2001 From: Ihor Sychevskyi <26163841+Arhell@users.noreply.github.com> Date: Mon, 24 Feb 2020 08:50:47 +0200 Subject: [PATCH 077/111] Fix anchor in readme (#19271) --- README-fr.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README-fr.md b/README-fr.md index cca46595ad..37350a5b81 100644 --- a/README-fr.md +++ b/README-fr.md @@ -33,7 +33,7 @@ La façon recommandée d'exécuter le site web Kubernetes localement est d'utili > Si vous êtes sous Windows, vous aurez besoin de quelques outils supplémentaires que vous pouvez installer avec [Chocolatey](https://chocolatey.org). `choco install install make` -> Si vous préférez exécuter le site Web localement sans Docker, voir [Exécuter le site localement avec Hugo](#running-the-site-locally-using-hugo) ci-dessous. +> Si vous préférez exécuter le site Web localement sans Docker, voir [Exécuter le site localement avec Hugo](#exécuter-le-site-localement-en-utilisant-hugo) ci-dessous. Si vous avez Docker [up and running](https://www.docker.com/get-started), construisez l'image Docker `kubernetes-hugo' localement: From 646b7a5f633791de222e0c511383106e8fcf77b2 Mon Sep 17 00:00:00 2001 From: Rajesh Deshpande Date: Mon, 24 Feb 2020 22:44:48 +0530 Subject: [PATCH 078/111] Adding reference to node concept page. (#19263) * Adding reference to node concept page. This page discuss about assigning pods to the node but missing reference to the node concept page. So for better navigation added this reference in what's next section * Correcting syntax Correcting syntax * Adding glossary tooltip for 'node' Adding glossary tooltip for 'node' --- .../docs/tasks/configure-pod-container/assign-pods-nodes.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/en/docs/tasks/configure-pod-container/assign-pods-nodes.md b/content/en/docs/tasks/configure-pod-container/assign-pods-nodes.md index 5b6b78a536..b5f6876e6b 100644 --- a/content/en/docs/tasks/configure-pod-container/assign-pods-nodes.md +++ b/content/en/docs/tasks/configure-pod-container/assign-pods-nodes.md @@ -19,7 +19,7 @@ Kubernetes cluster. ## Add a label to a node -1. List the nodes in your cluster, along with their labels: +1. List the {{< glossary_tooltip term_id="node" text="nodes" >}} in your cluster, along with their labels: ```shell kubectl get nodes --show-labels @@ -97,7 +97,7 @@ Use the configuration file to create a pod that will get scheduled on `foo-node` {{% /capture %}} {{% capture whatsnext %}} -Learn more about -[labels and selectors](/docs/concepts/overview/working-with-objects/labels/). +* Learn more about [labels and selectors](/docs/concepts/overview/working-with-objects/labels/). +* Learn more about [nodes](/docs/concepts/architecture/nodes/). {{% /capture %}} From 0181d882199b8ed95d9507ea0069b001e3cbd06e Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Mon, 24 Feb 2020 21:14:49 +0300 Subject: [PATCH 079/111] Translate Reference Docs Overview section into Russian (#19284) --- .../contribute/generate-ref-docs/_index.md | 11 + .../generate-ref-docs/contribute-upstream.md | 185 +++++++++++++++ .../contribute/generate-ref-docs/kubectl.md | 224 ++++++++++++++++++ .../generate-ref-docs/kubernetes-api.md | 188 +++++++++++++++ .../kubernetes-components.md | 32 +++ .../generate-ref-docs/quickstart.md | 220 +++++++++++++++++ .../ru/docs/templates/feature-state-alpha.txt | 7 + .../ru/docs/templates/feature-state-beta.txt | 8 + .../templates/feature-state-deprecated.txt | 2 + .../docs/templates/feature-state-stable.txt | 5 + content/ru/docs/templates/index.md | 13 + content/ru/includes/prerequisites-ref-docs.md | 20 ++ i18n/ru.toml | 2 +- 13 files changed, 916 insertions(+), 1 deletion(-) create mode 100644 content/ru/docs/contribute/generate-ref-docs/_index.md create mode 100644 content/ru/docs/contribute/generate-ref-docs/contribute-upstream.md create mode 100644 content/ru/docs/contribute/generate-ref-docs/kubectl.md create mode 100644 content/ru/docs/contribute/generate-ref-docs/kubernetes-api.md create mode 100644 content/ru/docs/contribute/generate-ref-docs/kubernetes-components.md create mode 100644 content/ru/docs/contribute/generate-ref-docs/quickstart.md create mode 100644 content/ru/docs/templates/feature-state-alpha.txt create mode 100644 content/ru/docs/templates/feature-state-beta.txt create mode 100644 content/ru/docs/templates/feature-state-deprecated.txt create mode 100644 content/ru/docs/templates/feature-state-stable.txt create mode 100644 content/ru/docs/templates/index.md create mode 100644 content/ru/includes/prerequisites-ref-docs.md diff --git a/content/ru/docs/contribute/generate-ref-docs/_index.md b/content/ru/docs/contribute/generate-ref-docs/_index.md new file mode 100644 index 0000000000..ac25aa014c --- /dev/null +++ b/content/ru/docs/contribute/generate-ref-docs/_index.md @@ -0,0 +1,11 @@ +--- +title: Обзор справочной документации +main_menu: true +weight: 80 +--- + +Темы в этом разделе описывают, как генерировать справочные руководства Kubernetes. + +Для сборки справочной документации посмотрите следующий ресурс: + +* [Краткое руководство по генерации справочной документации](/docs/contribute/generate-ref-docs/quickstart/) diff --git a/content/ru/docs/contribute/generate-ref-docs/contribute-upstream.md b/content/ru/docs/contribute/generate-ref-docs/contribute-upstream.md new file mode 100644 index 0000000000..07fe564753 --- /dev/null +++ b/content/ru/docs/contribute/generate-ref-docs/contribute-upstream.md @@ -0,0 +1,185 @@ +--- +title: Участие в основном коде Kubernetes +content_template: templates/task +weight: 20 +--- + +{{% capture overview %}} + +На этой странице показано, как поучаствовать в основном содержимом проекта `kubernetes/kubernetes`. +Вы можете исправить баги, найденные в документации по API Kubernetes или содержимом таких компонентов Kubernetes, как `kubeadm`, `kube-apiserver` и `kube-controller-manager`. + +Если вместо этого вы хотите перегенерировать справочную документацию для API Kubernetes или компонентов с именем `kube-*` в основном коде, изучите следующие инструкции: + +- [Генерация справочной документации для API Kubernetes](/ru/docs/contribute/generate-ref-docs/kubernetes-api/) +- [Генерация справочной документации для компонентов и инструментов Kubernetes](/ru/docs/contribute/generate-ref-docs/kubernetes-components/) + +{{% /capture %}} + +{{% capture prerequisites %}} + +- Установленные инструменты: + + - [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) + - [Golang](https://golang.org/doc/install) версии 1.13+ + - [Docker](https://docs.docker.com/engine/installation/) + - [etcd](https://github.com/coreos/etcd/) + +- Созданная переменная окружения `GOPATH`, а путь к `etcd` должен быть прописан в переменной окружения `PATH`. + +- Вам необходимо знать, как создать пулреквест в репозитории на GitHub. + Это обычно предполагает создание копии репозитория. + Для получения дополнительной информации смотрите страницы [Создание пулреквеста](https://help.github.com/articles/creating-a-pull-request/) и [Стандартный рабочий процесс в GitHub по работе с копией и пулреквестом](https://gist.github.com/Chaser324/ce0505fbed06b947d962). + +{{% /capture %}} + +{{% capture steps %}} + +## Рассмотрение процесса в целом + +Справочная документация для API Kubernetes и таких компонентов с `kube-*`, как `kube-apiserver`, `kube-controller-manager`, автоматически генерируются из исходного кода в [основном репозитории Kubernetes](https://github.com/kubernetes/kubernetes/). + +Если вы заметили баги в сгенерированной документации, попробуйте его исправить через пулреквест в основной проект. + +## Клонирование репозитория Kubernetes + +Если вы ещё не склонировали репозиторий kubernetes/kubernetes, сделайте это: + +```shell +mkdir $GOPATH/src +cd $GOPATH/src +go get github.com/kubernetes/kubernetes +``` + +Определите базовую директорию вашей копии репозитория [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes). +Например, если вы выполнили предыдущий шаг, чтобы получить репозиторий, вашей базовой директорией будет `$GOPATH/src/github.com/kubernetes/kubernetes`. +В остальных команд базовая директория будет именоваться как ``. + +Определите базовую директорию вашей копии репозитория [kubernetes-sigs/reference-docs](https://github.com/kubernetes-sigs/reference-docs). Например, если вы выполнили предыдущий шаг, чтобы получить репозиторий, вашей базовой директорией будет `$GOPATH/src/github.com/kubernetes-sigs/reference-docs`. +В остальных команд базовая директория будет именоваться как ``. + +## Редактирование исходного кода Kubernetes + +Справочная документация API Kubernetes генерируется автоматически из спецификации OpenAPI в исходном коде Kubernetes. Если вы хотите изменить справочную документацию API, сначала нужно изменить один или несколько комментариев в исходном коде Kubernetes. + +Документация для компонентов `kube-*` также генерируется из основного исходного кода. Для изменения генерируемой документации вам нужно изменить соответствующий код компонента. + +### Внесение изменений в основной исходный код + +{{< note >}} +Следующие шаги служат примером, а не общим порядком действий. Детали могут отличаться в вашей ситуации. +{{< /note >}} + +Рассмотрим пример редактирования комментария в исходном коде Kubernetes. + +В вашем локальном репозитории kubernetes/kubernetes переключитесь на ветку master и проверьте, что она актуальна: + +```shell +cd +git checkout master +git pull https://github.com/kubernetes/kubernetes master +``` + +Предположим, что в исходном файле в ветке master есть опечатка "atmost": + +[kubernetes/kubernetes/staging/src/k8s.io/api/apps/v1/types.go](https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/api/apps/v1/types.go) + +В вашем локальном окружении откройте `types.go` и измените "atmost" на "at most". + +Убедитесь, что вы изменили файл: + +```shell +git status +``` + +Вывод этой команды покажет, что вы находитесь в ветке master и был изменён исходный файл `types.go`: + +```shell +On branch master +... + modified: staging/src/k8s.io/api/apps/v1/types.go +``` + +### Фиксация отредактированного файла + +Выполните команду `git add` и `git commit`, чтобы зафиксировать внесенные вами изменения. На следующем шаге вы сделаете второй коммит. Следует отметить, что ваши изменения должны быть разделены на коммита. + +### Генерация спецификации OpenAPI и сопутствующих файлов + +Перейдите в директорию `` и выполните следующие скрипты: + +```shell +hack/update-generated-swagger-docs.sh +hack/update-openapi-spec.sh +hack/update-generated-protobuf.sh +hack/update-api-reference-docs.sh +``` + +Выполните команду `git status`, чтобы посмотреть, какие файлы изменились. + +```shell +On branch master +... + modified: api/openapi-spec/swagger.json + modified: api/swagger-spec/apps_v1.json + modified: docs/api-reference/apps/v1/definitions.html + modified: staging/src/k8s.io/api/apps/v1/generated.proto + modified: staging/src/k8s.io/api/apps/v1/types.go + modified: staging/src/k8s.io/api/apps/v1/types_swagger_doc_generated.go +``` + +Изучите содержимое файла `api/openapi-spec/swagger.json`, чтобы убедиться в том, что опечатка была исправлена. +Например, для этого вы можете выполнить команду `git diff -a api/openapi-spec/swagger.json`. +Это важно, потому что изменённый файл `swagger.json` является результатом второй стадии процесса генерации документации. + +Выполните команду `git add` и `git commit` для фиксации ваших изменения. Теперь вы можете увидеть два новых коммита: +первый содержит отредактированный файл `types.go`, а второй — сгенерированную спецификацию OpenAPI и сопутствующие файлы. Оформляйте эти изменения в виде двух отдельных коммитов. Это означает, что не нужно объединять коммиты. + +Отправьте свои изменения как [пулреквест](https://help.github.com/articles/creating-a-pull-request/) в ветку master репозитория [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes). +Отслеживайте пулреквест и по мере необходимости отвечайте на комментарии рецензента. Не забывайте отслеживать активность в пулреквест до тех пор, пока он не будет принят. + +[PR 57758](https://github.com/kubernetes/kubernetes/pull/57758) — пример пулреквеста, который исправляет опечатку в исходном коде Kubernetes. + +{{< note >}} +Не всегда легко правильно определить, какой исходный файл нужно изменить. В предыдущем примере нужный исходный файл находится в директории `staging` в репозитории `kubernetes/kubernetes`. Однако в вашей ситуации файл для изменения может находится в другом месте, нежели чем в директории `staging`. Для получения помощи изучите файлы `README` в репозитории [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes/tree/master/staging) и в смежных репозиториях, например, [kubernetes/apiserver](https://github.com/kubernetes/apiserver/blob/master/README.md). +{{< /note >}} + +### Применение вашего коммита в ветку выпуска + +В предыдущем разделе вы отредактировали файл в ветке master, а затем запустили скрипты для генерации спецификации OpenAPI и смежных файлов. Затем вы отправили свои изменения в виде пулреквеста в ветку master репозитория kubernetes/kubernetes. Теперь представим, что вам нужно бэкпортировать изменения в ветку выпуска. К примеру, ветка master используется для разработки Kubernetes версии 1.10, а вы хотите применить ваши изменения в ветке release-1.9. + +Напомним, что в вашем пулреквесте есть два коммита: первый для редактирования `types.go`, а второй — для файлов, сгенерированных скриптами. Следующий шаг — применить сделанный вами первый коммит в ветку release-1.9. Суть в том, чтобы выбрать коммит, который изменяет файл `types.go`, а не коммит с результатами выполнения скриптов. За инструкциями обратитесь к странице [Propose a Cherry Pick](https://git.k8s.io/community/contributors/devel/sig-release/cherry-picks.md). + +{{< note >}} +Применение коммита требует наличия возможности добавить метку и этап в вашем пулреквесте. Если у вас нет таких разрешений, вам нужно переговорить с кем-то, кто может сделать это для вас. +{{< /note >}} + +Когда в вашем пулреквесте есть определённый коммит, который нужно применить в ветке release-1.9, вам нужно запустить перечисленные ниже скрипты в этой вете из вашего локального окружения. + +```shell +hack/update-generated-swagger-docs.sh +hack/update-openapi-spec.sh +hack/update-generated-protobuf.sh +hack/update-api-reference-docs.sh +``` + +Теперь зафиксируйте изменения в вашем пулреквесте с применённым коммитом, теперь там будет сгенерированная спецификация OpenAPI и связанные с ней файлы. Отслеживайте этот пулреквест до тех пор, пока он не будет объединен в ветке release-1.9. + +Сейчас у вас и в ветке master, и в ветке release-1.9 есть обновленный файл `types.go` вместе с множеством сгенерированных файлов, в которых отражаются изменения, внесенные вами в `types.go`. Обратите внимание, что сгенерированная спецификация OpenAPI и другие сгенерированные файлы в ветке release-1.9 не обязательно совпадают с сгенерированными файлами в ветке master. Сгенерированные файлы в ветке release-1.9 содержат элементы API только из Kubernetes 1.9. Сгенерированные файлы в ветке master могут содержать элементы API не только для версии 1.9, но и для 1.10, которая ещё находится в разработке. + +## Генерация справочной документации + +В предыдущем разделе было показано, как отредактировать исходный файл, а затем сгенерировать несколько файлов, включая `api/openapi-spec/swagger.json` в репозитории `kubernetes/kubernetes`. +Файл `swagger.json` — это файл определения OpenAPI, который используется для генерации справочной документации API. + +Теперь вы можете приступить к изучению руководству [Генерация справочной документации для API Kubernetes](/ru/docs/contribute/generate-ref-docs/kubernetes-api/), чтобы создать [справочную документацию API Kubernetes](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/). + +{{% /capture %}} + +{{% capture whatsnext %}} + +* [Генерация справочной документации для API Kubernetes](/ru/docs/contribute/generate-ref-docs/kubernetes-api/) +* [Генерация справочной документации для компонентов и инструментов Kubernetes](/ru/docs/contribute/generate-ref-docs/kubernetes-components/) +* [Генерация справочной документации для команд kubectl](/ru/docs/contribute/generate-ref-docs/kubectl/) + +{{% /capture %}} diff --git a/content/ru/docs/contribute/generate-ref-docs/kubectl.md b/content/ru/docs/contribute/generate-ref-docs/kubectl.md new file mode 100644 index 0000000000..df75084ab8 --- /dev/null +++ b/content/ru/docs/contribute/generate-ref-docs/kubectl.md @@ -0,0 +1,224 @@ +--- +title: Генерация справочной документации для команд kubectl +content_template: templates/task +weight: 90 +--- + +{{% capture overview %}} + +На этой странице показано, как сгенерировать справочник для команды `kubectl`. + +{{< note >}} +На этой странице показывается, как сгенерировать справочную документацию для таких [команд kubectl](/ru/docs/reference/generated/kubectl/kubectl-commands), как [kubectl apply](/ru/docs/reference/generated/kubectl/kubectl-commands#apply) и [kubectl taint](/ru/docs/reference/generated/kubectl/kubectl-commands#taint). +Этот раздел не рассматривает генерацию справочной страницы для опций [kubectl](/ru/docs/reference/generated/kubectl/kubectl/). Инструкции по генерации справочной страницы опций kubectl смотрите в разделе [Генерация справочной документации для компонентов и инструментов Kubernetes](/ru/docs/contribute/generate-ref-docs/kubernetes-components/). +{{< /note >}} + +{{% /capture %}} + +{{% capture prerequisites %}} + +{{< include "prerequisites-ref-docs.md" >}} + +{{% /capture %}} + +{{% capture steps %}} + +## Настройка локальных репозиториев + +Создайте рабочую область и определите переменную окружения `GOPATH`. + +```shell +mkdir -p $HOME/ + +export GOPATH=$HOME/ +``` + +Загрузите локальные копии следующих репозиториев: + +```shell +go get -u github.com/spf13/pflag +go get -u github.com/spf13/cobra +go get -u gopkg.in/yaml.v2 +go get -u kubernetes-sigs/reference-docs +``` + +Если у вас ещё нет копии репозитория kubernetes/website, клонируйте её на свой компьютер: + +```shell +git clone https://github.com//website $GOPATH/src/github.com//website +``` + +Склонируйте репозиторий kubernetes/kubernetes по пути k8s.io/kubernetes: + +```shell +git clone https://github.com/kubernetes/kubernetes $GOPATH/src/k8s.io/kubernetes +``` + +Удалите пакет spf13 в `$GOPATH/src/k8s.io/kubernetes/vendor/github.com`. + +```shell +rm -rf $GOPATH/src/k8s.io/kubernetes/vendor/github.com/spf13 +``` + +В репозитории kubernetes/kubernetes использует исходный код `kubectl` и `kustomize`. + +* Определите базовую директорию вашей копии репозитория [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes). +Например, если вы выполнили предыдущий шаг, чтобы получить репозиторий, вашей базовой директорией будет `$GOPATH/src/k8s.io/kubernetes`. +В остальных командах базовая директория будет именоваться как ``. + +* Определите базовую директорию вашей копии репозитория [kubernetes/website](https://github.com/kubernetes/website). +Например, если вы выполнили предыдущий шаг, чтобы получить репозиторий, вашей базовой директорией будет `$GOPATH/src/github.com//website`. +В остальных команд базовая директория будет именоваться как ``. + +* Определите базовую директорию вашей копии репозитория [kubernetes-sigs/reference-docs](https://github.com/kubernetes-sigs/reference-docs). +Например, если вы выполнили предыдущий шаг, чтобы получить репозиторий, вашей базовой директорией будет `$GOPATH/src/github.com/kubernetes-sigs/reference-docs`. +В остальных команд базовая директория будет именоваться как ``. + +В вашем локальном репозитории k8s.io/kubernetes переключитесь в нужную вам ветку и убедитесь, что она в актуальном состоянии. Например, если вам нужно сгенерировать документацию для Kubernetes 1.17, вы можете использовать эти команды: + +```shell +cd +git checkout v1.17.0 +git pull https://github.com/kubernetes/kubernetes v1.17.0 +``` + +Если вам не нужно изменять исходный код `kubectl`, следуйте инструкциям по [определению переменных сборки](#настройка-переменных-для-сборки). + +## Редактирование исходного кода kubectl + +Справочная документация по команде kubectl генерируется автоматически из исходного кода kubectl. Если вы хотите изменить справочную документацию, сначала измените один или несколько комментариев в исходном коде kubectl. Сделайте изменения в локальный репозиторий kubernetes/kubernetes, а затем отправьте пулреквест в ветку master репозитория [github.com/kubernetes/kubernetes](https://github.com/kubernetes/kubernetes). + +[PR 56673](https://github.com/kubernetes/kubernetes/pull/56673/files) — пример пулреквеста, который исправляет опечатку в исходном коде kubectl. + +Отслеживайте пулреквест и по мере необходимости отвечайте на комментарии рецензента. Не забывайте отслеживать активность в пулреквест до тех пор, пока он не будет принят в ветку master репозитория kubernetes/kubernetes. + +## Применение вашего изменения в ветку выпуска + +Теперь ваше изменение в ветке master, которая используется для разработки следующего выпуска Kubernetes. Если вы хотите добавить ваше изменение в документацию для уже выпущенной версии Kubernetes, вам нужно применить коммит с соответствующим изменением в нужную ветку выпуска. + +Например, предположим, что ветка master используется для разработки Kubernetes 1.10, а вам нужно бэкпортировать ваше изменение в ветку release-1.15. За инструкциями обратитесь к странице [Propose a Cherry Pick](https://git.k8s.io/community/contributors/devel/sig-release/cherry-picks.md). + +Отслеживайте ваш пулреквест с применённым изменением до тех пор, пока он не будет объединён в ветку выпуска. + +{{< note >}} +Применение коммита требует наличия возможности добавить метку и этап в вашем пулреквесте. Если у вас нет таких разрешений, вам нужно переговорить с кем-то, кто может сделать это для вас. +{{< /note >}} + +## Настройка переменных для сборки + +Перейдите на ``. В командной строке установите следующие переменные окружения. + +* `K8S_ROOT` со значением ``. +* `WEB_ROOT` со значением ``. +* `K8S_RELEASE` со значением нужной версии документации. + Например, если вы хотите собрать документацию для Kubernetes версии 1.17, определите переменную окружения `K8S_RELEASE` со значением 1.17. + +Примеры: + +```shell +export WEB_ROOT=$(GOPATH)/src/github.com//website +export K8S_ROOT=$(GOPATH)/src/k8s.io/kubernetes +export K8S_RELEASE=1.17 +``` + +## Создание версионированной директории + +Скрипт сборки `createversiondirs` создаёт версионированную директорию и копирует туда конфигурационные файлы справочника kubectl. +Имя версионированной директории имеет следующий вид: `v_`. + +В директории `` выполнение следующий скрипт сборки: + +```shell +cd +make createversiondirs +``` + +## Переход в тег выпуска в k8s.io/kubernetes + +В вашем локальном репозитории `` перейдите в ветку с версией Kubernetes, для которой вы хотите получить документацию. Например, если вы хотите сгенерировать документацию для Kubernetes 1.17, перейдите в тег `v1.17.0`. Убедитесь, что ваша локальная ветка содержит актуальные изменения. + +```shell +cd +git checkout v1.17.0 +git pull https://github.com/kubernetes/kubernetes v1.17.0 +``` + +## Выполнение кода для генерации документации + +В вашей локальной директории `` запустите скрипт сборки `copycli`. Команда выполняется от пользователя `root`: + +```shell +cd +make copycli +``` + +Команда `copycli` удаляет временную директорию сборки, генерирует файлы команды kubectl и копирует полученную HTML-страницу справочника команде kubectl и ресурсы в ``. + +## Проверка сгенерированных файлов + +Убедитесь в том, что перечисленные ниже два файлы были сгенерированы: + +```shell +[ -e "/gen-kubectldocs/generators/build/index.html" ] && echo "index.html built" || echo "no index.html" +[ -e "/gen-kubectldocs/generators/build/navData.js" ] && echo "navData.js built" || echo "no navData.js" +``` + +## Проверка скопированных файлов + +Убедитесь в том, все сгенерированные файлы были скопированы в вашу директорию ``: + +```shell +cd +git status +``` + +В выводе должны перечислены изменённые файлы: + +``` +static/docs/reference/generated/kubectl/kubectl-commands.html +static/docs/reference/generated/kubectl/navData.js +``` + +Также в выводе должно быть: + +``` +static/docs/reference/generated/kubectl/scroll.js +static/docs/reference/generated/kubectl/stylesheet.css +static/docs/reference/generated/kubectl/tabvisibility.js +static/docs/reference/generated/kubectl/node_modules/bootstrap/dist/css/bootstrap.min.css +static/docs/reference/generated/kubectl/node_modules/highlight.js/styles/default.css +static/docs/reference/generated/kubectl/node_modules/jquery.scrollto/jquery.scrollTo.min.js +static/docs/reference/generated/kubectl/node_modules/jquery/dist/jquery.min.js +static/docs/reference/generated/kubectl/node_modules/font-awesome/css/font-awesome.min.css +``` + +## Проверка документации локально + +Соберите документацию Kubernetes в вашей директории ``. + +```shell +cd +make docker-serve +``` + +Посмотрите [локальную предварительную версию сайта](https://localhost:1313/docs/reference/generated/kubectl/kubectl-commands/). + +## Добавление и фиксация изменений в kubernetes/website + +Выполните команду `git add` и `git commit` для фиксации файлов. + +## Создание пулреквеста + +Создайте пулреквест в репозиторий `kubernetes/website`. Отслеживайте изменения в пулреквесте и по мере необходимости отвечайте на комментарии рецензента. Не забывайте проверять пулреквест до тех пор, пока он не будет принят. + +Спустя несколько минут после принятия вашего пулреквеста, обновленные темы справочника будут отображены в [документации](/ru/docs/home/). + +{{% /capture %}} + +{{% capture whatsnext %}} + +* [Руководство по быстрому старту генерации справочной документации](/ru/docs/contribute/generate-ref-docs/quickstart/) +* [Генерация справочной документации для компонентов и инструментов Kubernetes](/ru/docs/contribute/generate-ref-docs/kubernetes-components/) +* [Генерация справочной документации для API Kubernetes](/ru/docs/contribute/generate-ref-docs/kubernetes-api/) + +{{% /capture %}} diff --git a/content/ru/docs/contribute/generate-ref-docs/kubernetes-api.md b/content/ru/docs/contribute/generate-ref-docs/kubernetes-api.md new file mode 100644 index 0000000000..68f5ad1199 --- /dev/null +++ b/content/ru/docs/contribute/generate-ref-docs/kubernetes-api.md @@ -0,0 +1,188 @@ +--- +title: Генерация справочной документации для API Kubernetes +content_template: templates/task +weight: 50 +--- + +{{% capture overview %}} + +На этой странице рассказывается про обновление справочной документации по API Kubernetes. + +Справочная документация по API Kubernetes собирается из [спецификации OpenAPI Kubernetes](https://github.com/kubernetes/kubernetes/blob/master/api/openapi-spec/swagger.json) с использованием инструмента генерации [kubernetes-sigs/reference-docs](https://github.com/kubernetes-sigs/reference-docs). + +Если вы нашли баги в сгенерированной документации, то можете [исправить их в основном коде](/docs/contribute/generate-ref-docs/contribute-upstream/). + +Продолжайте чтение данной странице, если вы хотите перегенерировать справочную документацию из спецификации [OpenAPI](https://github.com/OAI/OpenAPI-Specification). + +{{% /capture %}} + +{{% capture prerequisites %}} + +{{< include "prerequisites-ref-docs.md" >}} + +{{% /capture %}} + +{{% capture steps %}} + +## Настройка локальных репозиториев + +Создайте рабочую область и определите переменную окружения `GOPATH`. + +```shell +mkdir -p $HOME/ + +export GOPATH=$HOME/ +``` + +Загрузите локальные копии следующих репозиториев: + +```shell +go get -u github.com/kubernetes-sigs/reference-docs + +go get -u github.com/go-openapi/loads +go get -u github.com/go-openapi/spec +``` + +Если у вас ещё нет копии репозитория kubernetes/website, клонируйте её на свой компьютер: + +```shell +git clone https://github.com//website $GOPATH/src/github.com//website +``` + +Склонируйте репозиторий kubernetes/kubernetes по пути k8s.io/kubernetes: + +```shell +git clone https://github.com/kubernetes/kubernetes $GOPATH/src/k8s.io/kubernetes +``` + +* Определите базовую директорию вашей копии репозитория [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes). +Например, если вы выполнили предыдущий шаг, чтобы получить репозиторий, вашей базовой директорией будет `$GOPATH/src/k8s.io/kubernetes`. +В остальных командах базовая директория будет именоваться как ``. + +* Определите базовую директорию вашей копии репозитория [kubernetes/website](https://github.com/kubernetes/website). +Например, если вы выполнили предыдущий шаг, чтобы получить репозиторий, вашей базовой директорией будет `$GOPATH/src/github.com//website`. +В остальных командах базовая директория будет именоваться как ``. + +* Определите базовую директорию вашей копии репозитория [kubernetes-sigs/reference-docs](https://github.com/kubernetes-sigs/reference-docs). +Например, если вы выполнили предыдущий шаг, чтобы получить репозиторий, вашей базовой директорией будет `$GOPATH/src/github.com/kubernetes-sigs/reference-docs`. +В остальных командах базовая директория будет именоваться как ``. + +## Генерация справочной документации API + +Далее в этом разделе рассматривается генерация [справочной документации по API Kubernetes](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/). + +### Настройка переменных для сборки + +* `K8S_ROOT` со значением ``. +* `WEB_ROOT` со значением ``. +* `K8S_RELEASE` со значением нужной версии документации. + Например, если вы хотите собрать документацию для Kubernetes версии 1.17, определите переменную окружения `K8S_RELEASE` со значением 1.17. + +Примеры: + +```shell +export WEB_ROOT=$(GOPATH)/src/github.com//website +export K8S_ROOT=$(GOPATH)/src/k8s.io/kubernetes +export K8S_RELEASE=1.17 +``` + +### Создание версионированной директории и получение Open API spec + +Скрипт сборки `updateapispec` создает версионированную директорию для сборки. +После создания директории спецификация Open API генерируется из репозитория ``. Таким образом версия конфигурационных файлов и спецификация Kubernetes Open API будут совпадать с версией выпуска. +Имя версионированной директории имеет следующий вид: `v_`. + +В директории `` выполните следующий скрипт сборки: + +```shell +cd +make updateapispec +``` + +### Сборка справочной документации API + +Скрипт сборки `copyapi` создает справочник API и копирует генерированные файлы в каталоги в ``. +Выполните следующую команду в ``: + +```shell +cd +make copyapi +``` + +Убедитесь в том, что перечисленные ниже два файлы были сгенерированы: + +```shell +[ -e "/gen-apidocs/generators/build/index.html" ] && echo "index.html built" || echo "no index.html" +[ -e "/gen-apidocs/generators/build/navData.js" ] && echo "navData.js built" || echo "no navData.js" +``` + +Перейдите в корень директории `` и посмотрите, какие файлы были изменены: + +```shell +cd +git status +``` + +Вывод команды будет примерно следующим: + +``` +static/docs/reference/generated/kubernetes-api/v1.17/css/bootstrap.min.css +static/docs/reference/generated/kubernetes-api/v1.17/css/font-awesome.min.css +static/docs/reference/generated/kubernetes-api/v1.17/css/stylesheet.css +static/docs/reference/generated/kubernetes-api/v1.17/fonts/FontAwesome.otf +static/docs/reference/generated/kubernetes-api/v1.17/fonts/fontawesome-webfont.eot +static/docs/reference/generated/kubernetes-api/v1.17/fonts/fontawesome-webfont.svg +static/docs/reference/generated/kubernetes-api/v1.17/fonts/fontawesome-webfont.ttf +static/docs/reference/generated/kubernetes-api/v1.17/fonts/fontawesome-webfont.woff +static/docs/reference/generated/kubernetes-api/v1.17/fonts/fontawesome-webfont.woff2 +static/docs/reference/generated/kubernetes-api/v1.17/index.html +static/docs/reference/generated/kubernetes-api/v1.17/js/jquery.scrollTo.min.js +static/docs/reference/generated/kubernetes-api/v1.17/js/navData.js +static/docs/reference/generated/kubernetes-api/v1.17/js/scroll.js +``` + +## Обновление указателя API-справочника + +При генерации справочной документации для нового выпуска в файле `/content/en/docs/reference/kubernetes-api/api-index.md` нужно прописать номер предстоящей версии. + +* Откройте файл `/content/en/docs/reference/kubernetes-api/api-index.md` и обновите номер версии справочника API. Например: + + ``` + --- + title: v1.17 + --- + + [Kubernetes API v1.17](/docs/reference/generated/kubernetes-api/v1.17/) + ``` + +* Откройте файл `/content/en/docs/reference/_index.md` и добавьте ссылку на последний справочник API. Удалите самую старую версию справочника API. + В этом файле должно быть 5 ссылок на новейшие API-справочники. + +## Тестирование справочника API локально + +Соберите обновлённую версию API-справочника на своём компьютере. +Проверьте ваши изменения на [локальной предварительной версии сайта](http://localhost:1313/docs/reference/generated/kubernetes-api/v1.17/). + +```shell +cd +make docker-serve +``` + +## Фиксация изменений + +В директории `` выполните команду `git add` и `git commit` для фиксации изменений в репозитории. + +Создайте пулреквест в репозиторий `kubernetes/website`. Отслеживайте свой пулреквест и при необходимости отвечайте на комментарии. Не забывайте отслеживать активность в собственном пулреквесте до тех пор, пока он не будет принят. + +Отправьте свои изменения в виде [пулреквеста](/ru/docs/contribute/start/) в репозиторий [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes). +Отслеживайте изменения в пулреквесте и по мере необходимости отвечайте на комментарии рецензента. Не забывайте проверять пулреквест до тех пор, пока он не будет принят. + +{{% /capture %}} + +{{% capture whatsnext %}} + +* [Руководство по быстрому старту генерации справочной документации](/ru/docs/contribute/generate-ref-docs/quickstart/) +* [Генерация справочной документации для компонентов и инструментов Kubernetes](/ru/docs/contribute/generate-ref-docs/kubernetes-components/) +* [Генерация справочной документации для команд kubectl](/ru/docs/contribute/generate-ref-docs/kubectl/) + +{{% /capture %}} diff --git a/content/ru/docs/contribute/generate-ref-docs/kubernetes-components.md b/content/ru/docs/contribute/generate-ref-docs/kubernetes-components.md new file mode 100644 index 0000000000..194a496574 --- /dev/null +++ b/content/ru/docs/contribute/generate-ref-docs/kubernetes-components.md @@ -0,0 +1,32 @@ +--- +title: Генерация справочных страниц для компонентов и инструментов Kubernetes +content_template: templates/task +weight: 120 +--- + +{{% capture overview %}} + +На этой странице показывается, как собирать справочные страницы компонентов и инструментов Kubernetes. + +{{% /capture %}} + +{{% capture prerequisites %}} + +Начните с [раздела с требованиями](/ru/docs/contribute/generate-ref-docs/quickstart/#подготовка-к-работе) в руководстве по быстрому старту. + +{{% /capture %}} + +{{% capture steps %}} + +Для генерации справочных страниц компонентов и инструментов Kubernetes изучите страницу [руководство по быстрому старту в справочной документации](/docs/contribute/generate-ref-docs/quickstart/). + +{{% /capture %}} + +{{% capture whatsnext %}} + +* [Краткое руководство по генерации справочной документации](/ru/docs/contribute/generate-ref-docs/quickstart/) +* [Генерация справочной документации для команд kubectl](/ru/docs/contribute/generate-ref-docs/kubectl/) +* [Генерация справочной документации для API Kubernetes](/ru/docs/contribute/generate-ref-docs/kubernetes-api/) +* [Участие в документации основного кода проекта Kubernetes](/ru/docs/contribute/generate-ref-docs/contribute-upstream/) + +{{% /capture %}} diff --git a/content/ru/docs/contribute/generate-ref-docs/quickstart.md b/content/ru/docs/contribute/generate-ref-docs/quickstart.md new file mode 100644 index 0000000000..8fce407be0 --- /dev/null +++ b/content/ru/docs/contribute/generate-ref-docs/quickstart.md @@ -0,0 +1,220 @@ +--- +title: Руководство по быстрому старту +content_template: templates/task +weight: 40 +--- + +{{% capture overview %}} + +На этой странице показано, как использовать скрипт `update-imported-docs` для генерации справочной документации Kubernetes. Скрипт автоматизирует настройку сборки и генерирует справочную документацию для выпуска. + +{{% /capture %}} + +{{% capture prerequisites %}} + +{{< include "prerequisites-ref-docs.md" >}} + +{{% /capture %}} + +{{% capture steps %}} + +## Получение репозитория документации + +Убедитесь, что ваша копия репозитория `website` обновлена в соответствии с оригинальным репозиторием `kubernetes/website`, а затем склонируйте вашу копию `website`. + +```shell +mkdir github.com +cd github.com +git clone git@github.com:/website.git +``` + +Определите базовую директорию вашей копии. Например, при выполнении предыдущего блока команд, то базовой директорией будет `website`. Далее в этом руководстве базовая директория в командах будет обозначаться ``. + +{{< note>}} +Если вы хотите изменить контент инструментов компонента и справочник API, посмотрите [руководство по участию в оригинальной документации](/docs/contribute/generate-ref-docs/contribute-upstream). +{{< /note >}} + +## Краткий обзор update-imported-docs + +Скрипт `update-imported-docs` находится в директории `/update-imported-docs/`. + +Этот скрипт генерирует следующие справочники: + +* Справочные страницы для компонентов и инструментов +* Справочник команды `kubectl` +* API-справочник Kubernetes + +Скрипт `update-imported-docs` генерирует справочную документацию Kubernetes из исходного кода Kubernetes. Скрипт создает временную директорию `/tmp` на вашем компьютере и клонирует необходимые репозитории в эту директорию: `kubernetes/kubernetes` и `kubernetes-sigs/reference-docs`. +Скрипт добавляет путь временной директории в переменную окружения `GOPATH`. +Кроме этого определяются три дополнительные переменные среды: + +* `K8S_RELEASE` +* `K8S_ROOT` +* `K8S_WEBROOT` + +Для успешного выполнения скрипта нужно передать два аргумента: + +* Конфигурационный файл в формате YAML (`reference.yml`) +* Версия выпуска, например, `1.17` + +Конфигурационный файл содержит поле `generate-command`. +Поле `generate-command` определяет ряд инструкций для сборки из `kubernetes-sigs/reference-docs/Makefile`. Переменная `K8S_RELEASE` определяет версию выпуска. + +Скрипт `update-imported-docs` выполняет следующие шаги: + +1. Клонирует репозитории, указанные в конфигурационном файле. Для генерации справочной документации клонируемым репозиторием по умолчанию является `kubernetes-sigs/reference-docs`. +1. Запускает команды в клонированных репозиториях для подготовки генератора документации, а затем генерирует файлы HTML и Markdown. +1. Копирует сгенерированные файлы HTML и Markdown в локальную копию репозитория `` в директории, указанные в конфигурационном файле. +1. Обновляет ссылки на команды `kubectl` из `kubectl`.md, ссылаясь на разделы в справочнике по команде `kubectl`. +. +Когда сгенерированные файлы находятся в вашем локальной копии репозитория ``, вы можете отправить их в виде [пулреквеста](/ru/docs/contribute/start/) в оригинальный репозиторий ``. + +## Формат конфигурационного файла + +Каждый конфигурационный файл может содержать несколько репозиториев, которые будут импортированы вместе. При необходимости вы можете вручную изменить конфигурационный файл. Вы можете создавать новые конфигурационные файлы для импорта других групп документации. +Ниже приведен пример файла конфигурации в формате YAML: + +```yaml +repos: +- name: community + remote: https://github.com/kubernetes/community.git + branch: master + files: + - src: contributors/devel/README.md + dst: docs/imported/community/devel.md + - src: contributors/guide/README.md + dst: docs/imported/community/guide.md +``` + +Каждый Markdown-файл документации, импортированный инструментом, должен соответствовать [руководству по оформлению документации](/docs/contribute/style/style-guide/). + +## Настройка reference.yml + +Откройте файл `/update-imported-docs/reference.yml` для редактирования. +Не изменяйте значение в поле `generate-command`, если не понимаете, как эта команда используется для сборки справочников. +Вам нет необходимости править файл `reference.yml`. В некоторых случаях изменения в исходном коде основного репозитория могут потребовать внесения изменений в конфигурационный файл (например, зависимости версий golang и изменения сторонних библиотек). +Если у вас возникли проблемы со сборкой, обратитесь за помощью к команде SIG-Docs на канале [#sig-docs в Slack Kubernetes](https://kubernetes.slack.com). + +{{< note >}} +Команда `generate-command` является необязательной, её можно использовать для выполнения указанной команды или небольшого скрипта, чтобы сгенерировать документацию из репозитория. +{{< /note >}} + +В файле `reference.yml` секция `files` содержат список полей `src` и `dst`. +В поле `src` хранится путь к сгенерированному Markdown-файлу в клонированной директории сборки `kubernetes-sigs/reference-docs`, а поле `dst` определяет, куда скопировать этот файл в клонированном репозитории `kubernetes/website`. +Например: + +```yaml +repos: +- name: reference-docs + remote: https://github.com/kubernetes-sigs/reference-docs.git + files: + - src: gen-compdocs/build/kube-apiserver.md + dst: content/en/docs/reference/command-line-tools-reference/kube-apiserver.md + ... +``` + +Обратите внимание, что в случае наличия множества файлов, которые нужно скопировать из одной директории в другую, то для это можете воспользоваться подстановочными знаки в поле `src`. Вам нужно указать имя директории в поле `dst`. +Например: + +```yaml + files: + - src: gen-compdocs/build/kubeadm*.md + dst: content/en/docs/reference/setup-tools/kubeadm/generated/ +``` + +## Запуск инструмента update-imported-docs + +Вы можете запустить инструмент `update-imported-docs` следующим образом: + +```shell +cd /update-imported-docs +./update-imported-docs +``` + +Например: + +```shell +./update-imported-docs reference.yml 1.17 +``` + + +## Исправление ссылок + +Конфигурационный файл `release.yml` содержит инструкции по исправлению относительных ссылок +Для исправления относительных ссылок в импортированных файлах, установите для свойство `gen-absolute-links` в значение `true`. В качестве примера можете посмотреть файл [`release.yml`](https://github.com/kubernetes/website/blob/master/update-imported-docs/release.yml). + +## Внесение изменений в kubernetes/website + +Список сгенерированных и скопированных файлов в `` можно узнать, как показано ниже: + +```shell +cd +git status +``` + +В выводе команды будут показаны новые и измененные файлы. Полученный вывод может отличаться в зависимости от изменений основного исходного кода. + +### Сгенерированные файлы инструментом + +``` +content/en/docs/reference/command-line-tools-reference/cloud-controller-manager.md +content/en/docs/reference/command-line-tools-reference/kube-apiserver.md +content/en/docs/reference/command-line-tools-reference/kube-controller-manager.md +content/en/docs/reference/command-line-tools-reference/kube-proxy.md +content/en/docs/reference/command-line-tools-reference/kube-scheduler.md +content/en/docs/reference/setup-tools/kubeadm/generated/kubeadm.md +content/en/docs/reference/kubectl/kubectl.md +``` + +### Сгенерированные справочные файлы для команды kubectl + +``` +static/docs/reference/generated/kubectl/kubectl-commands.html +static/docs/reference/generated/kubectl/navData.js +static/docs/reference/generated/kubectl/scroll.js +static/docs/reference/generated/kubectl/stylesheet.css +static/docs/reference/generated/kubectl/tabvisibility.js +static/docs/reference/generated/kubectl/node_modules/bootstrap/dist/css/bootstrap.min.css +static/docs/reference/generated/kubectl/node_modules/highlight.js/styles/default.css +static/docs/reference/generated/kubectl/node_modules/jquery.scrollto/jquery.scrollTo.min.js +static/docs/reference/generated/kubectl/node_modules/jquery/dist/jquery.min.js +static/docs/reference/generated/kubectl/css/font-awesome.min.css +``` + +### Сгенерированные файлы и директории для справочника API Kubernetes + +``` +static/docs/reference/generated/kubernetes-api/v1.17/index.html +static/docs/reference/generated/kubernetes-api/v1.17/js/navData.js +static/docs/reference/generated/kubernetes-api/v1.17/js/scroll.js +static/docs/reference/generated/kubernetes-api/v1.17/js/query.scrollTo.min.js +static/docs/reference/generated/kubernetes-api/v1.17/css/font-awesome.min.css +static/docs/reference/generated/kubernetes-api/v1.17/css/bootstrap.min.css +static/docs/reference/generated/kubernetes-api/v1.17/css/stylesheet.css +static/docs/reference/generated/kubernetes-api/v1.17/fonts/FontAwesome.otf +static/docs/reference/generated/kubernetes-api/v1.17/fonts/fontawesome-webfont.eot +static/docs/reference/generated/kubernetes-api/v1.17/fonts/fontawesome-webfont.svg +static/docs/reference/generated/kubernetes-api/v1.17/fonts/fontawesome-webfont.ttf +static/docs/reference/generated/kubernetes-api/v1.17/fonts/fontawesome-webfont.woff +static/docs/reference/generated/kubernetes-api/v1.17/fonts/fontawesome-webfont.woff2 +``` + +Выполните `git add` и `git commit`, чтобы зафиксировать файлы в репозитории. + +## Создание пулреквеста + +Создайте пулреквест в репозиторий `kubernetes/website`. Отслеживайте свой пулреквест и при необходимости отвечайте на комментарии. Не забывайте отслеживать активность в собственном пулреквесте до тех пор, пока он не будет принят. + +Спустя несколько минут после принятия вашего пулреквеста, обновленные темы справочника будут отображены в [документации](/ru/docs/home/). + +{{% /capture %}} + +{{% capture whatsnext %}} + +Для генерации отдельной взятой справочной документации путём ручной настройки необходимых репозиториев сборки и выполнении скриптов сборки обратитесь к следующим руководствам: + +* [Генерация справочной документации для компонентов и инструментов Kubernetes](/ru/docs/contribute/generate-ref-docs/kubernetes-components/) +* [Генерация справочной документации для команд kubectl](/ru/docs/contribute/generate-ref-docs/kubectl/) +* [Генерация справочной документации для API Kubernetes](/ru/docs/contribute/generate-ref-docs/kubernetes-api/) + +{{% /capture %}} diff --git a/content/ru/docs/templates/feature-state-alpha.txt b/content/ru/docs/templates/feature-state-alpha.txt new file mode 100644 index 0000000000..ae3c2e8532 --- /dev/null +++ b/content/ru/docs/templates/feature-state-alpha.txt @@ -0,0 +1,7 @@ +В настоящее время данная функциональность находится в состоянии *alpha*, это означает, что: + +* Названия версий включают надпись "alpha" (например, v1alpha1). +* Могут быть баги. Работа с этой функциональностью может привести к ошибкам. Поэтому по умолчанию она отключена. +* Поддержка функциональности может быть прекращена в любое время без предупреждения. +* API может быть несовместим с более поздними версиями без предупреждения. +* Рекомендуется для использования только в тестировочных кластерах с коротким жизненным циклом из-за высокого риска наличия багов и отсутствия долгосрочной поддержки. \ No newline at end of file diff --git a/content/ru/docs/templates/feature-state-beta.txt b/content/ru/docs/templates/feature-state-beta.txt new file mode 100644 index 0000000000..7e4f0d91b6 --- /dev/null +++ b/content/ru/docs/templates/feature-state-beta.txt @@ -0,0 +1,8 @@ +В настоящее время данная функциональность находится в состоянии *beta*, это означает, что: + +* Названия версий включают надпись "beta" (например, v2beta3). +* Код хорошо протестирован. Активация этой функциональности — безопасно. Поэтому она включена по умолчанию. +* Поддержка функциональности в целом не будет прекращена, хотя детали могут измениться. +* Схема и/или семантика объектов может стать несовместимой с более поздними бета-версиями или стабильными выпусками. Когда это случится, мы даим инструкции по миграции на следующую версию. Это обновление может включать удаление, редактирование и повторного создание API-объектов. Этот процесс может потребовать тщательного анализа. Кроме этого, он может привести к простою приложений, которые используют данную функциональность. +* Рекомендуется только для неосновного производственного использования из-за риска возникновения возможных несовместимых изменений с будущими версиями. Если у вас есть несколько кластеров, которые возможно обновить независимо, вы можете снять это ограничение. +* **Пожалуйста, попробуйте в действии бета-версии функциональности и поделитесь своими впечатлениями! После того, как функциональность выйдет из бета-версии, нам может быть нецелесообразно что-то дальше изменять.** diff --git a/content/ru/docs/templates/feature-state-deprecated.txt b/content/ru/docs/templates/feature-state-deprecated.txt new file mode 100644 index 0000000000..c3ef2b815c --- /dev/null +++ b/content/ru/docs/templates/feature-state-deprecated.txt @@ -0,0 +1,2 @@ + +Данная функциональность объявлена *устаревшей*. Для получения дополнительной информации об этом состоянии перейдите на страницу [Политика управления устаревшими версиями Kubernetes](/docs/reference/deprecation-policy/). \ No newline at end of file diff --git a/content/ru/docs/templates/feature-state-stable.txt b/content/ru/docs/templates/feature-state-stable.txt new file mode 100644 index 0000000000..4e13386e62 --- /dev/null +++ b/content/ru/docs/templates/feature-state-stable.txt @@ -0,0 +1,5 @@ + +Данная функциональность является *стабильной*, это означает, что: + +* Версии именуются по шаблону vX, где X — это целое число. +* Стабильные версии функциональности будут доступны во многих последующих выпусках. \ No newline at end of file diff --git a/content/ru/docs/templates/index.md b/content/ru/docs/templates/index.md new file mode 100644 index 0000000000..9d7bccd143 --- /dev/null +++ b/content/ru/docs/templates/index.md @@ -0,0 +1,13 @@ +--- +headless: true + +resources: +- src: "*alpha*" + title: "alpha" +- src: "*beta*" + title: "beta" +- src: "*deprecated*" + title: "deprecated" +- src: "*stable*" + title: "stable" +--- diff --git a/content/ru/includes/prerequisites-ref-docs.md b/content/ru/includes/prerequisites-ref-docs.md new file mode 100644 index 0000000000..bc43abc19c --- /dev/null +++ b/content/ru/includes/prerequisites-ref-docs.md @@ -0,0 +1,20 @@ + +### Требования: + +- Наличие компьютера под управлением ОС Linux или macOS. + +- Установленные следующие инструменты: + + - [Python](https://www.python.org/downloads/) версии 3.7.x + - [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) + - [Golang](https://golang.org/doc/install) версии 1.13+ + - [Pip](https://pypi.org/project/pip/), который потребуется для установки PyYAML + - [PyYAML](https://pyyaml.org/) версии 5.1.2 + - [make](https://www.gnu.org/software/make/) + - [gcc compiler/linker](https://gcc.gnu.org/) + - [Docker](https://docs.docker.com/engine/installation/) (требуется только для справочника команды `kubectl`) + +- В переменной окружении `PATH` должны прописаны пути до необходимых инструментов сборки, таких как `Go` и `python`. + +- Вам нужно знать, как создать пулреквест в репозитории на GitHub. + Для этого нужно создание собственной копии репозитория. Для получения дополнительной информации смотрите раздел [Работа из локальной копии](/ru/docs/contribute/intermediate/#работа-из-локальной-копии). diff --git a/i18n/ru.toml b/i18n/ru.toml index 8e8b1c6275..19b8e21a1a 100644 --- a/i18n/ru.toml +++ b/i18n/ru.toml @@ -13,7 +13,7 @@ other = "Цели" other = "Очистка" [prerequisites_heading] -other = "Прежде чем вы начнете" +other = "Подготовка к работе" [whatsnext_heading] other = "Что дальше" From a5f2cece61fcd3de3a70d87aec05cf9f9f6964a7 Mon Sep 17 00:00:00 2001 From: Utwo Date: Mon, 24 Feb 2020 21:55:36 +0200 Subject: [PATCH 080/111] Fix form allignment in mobile view. (#17007) * Fix form alignement in mobile view * Remove margin left * Add mare space between input and button --- layouts/index.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/layouts/index.html b/layouts/index.html index f90e1d2439..d3fd401d78 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -14,6 +14,7 @@ @@ -27,7 +28,7 @@

{{ T "main_kubeweekly_past_link" }}
From b30415f6f986e5c30c7aa74849582d96bade0773 Mon Sep 17 00:00:00 2001 From: Tim Bannister Date: Tue, 25 Feb 2020 01:13:36 +0000 Subject: [PATCH 081/111] Note CronJob timezone comes from system timezone (#19269) * Note CronJob timezone comes from system timezone The timezone for the kube-controller-manager (or if that's broken apart, the cronjob controller) determines when CronJobs are scheduled. This reverts commit bad124b857a2927b75be739646244aacc5190580. * Expand details about CronJob timezone --- .../docs/concepts/workloads/controllers/cron-jobs.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/content/en/docs/concepts/workloads/controllers/cron-jobs.md b/content/en/docs/concepts/workloads/controllers/cron-jobs.md index 24492cd18c..c56467322b 100644 --- a/content/en/docs/concepts/workloads/controllers/cron-jobs.md +++ b/content/en/docs/concepts/workloads/controllers/cron-jobs.md @@ -17,9 +17,14 @@ A _Cron Job_ creates [Jobs](/docs/concepts/workloads/controllers/jobs-run-to-com One CronJob object is like one line of a _crontab_ (cron table) file. It runs a job periodically on a given schedule, written in [Cron](https://en.wikipedia.org/wiki/Cron) format. -{{< note >}} -All **CronJob** `schedule:` times are denoted in UTC. -{{< /note >}} +{{< caution >}} +All **CronJob** `schedule:` times are based on the timezone of the +{{< glossary_tooltip term_id="kube-controller-manager" text="kube-controller-manager" >}}. + +If your control plane runs the kube-controller-manager in Pods or bare +containers, the timezone set for the kube-controller-manager container determines the timezone +that the cron job controller uses. +{{< /caution >}} When creating the manifest for a CronJob resource, make sure the name you provide is no longer than 52 characters. This is because the CronJob controller will automatically From 63280bb7a5abe01e147cda7a0f3ac8df2c178d8f Mon Sep 17 00:00:00 2001 From: Bouimadaghene Date: Tue, 25 Feb 2020 09:48:48 +0100 Subject: [PATCH 082/111] fix typos (#19291) --- content/fr/docs/setup/custom-cloud/kubespray.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/fr/docs/setup/custom-cloud/kubespray.md b/content/fr/docs/setup/custom-cloud/kubespray.md index 0568cb2a1a..926295b7ac 100644 --- a/content/fr/docs/setup/custom-cloud/kubespray.md +++ b/content/fr/docs/setup/custom-cloud/kubespray.md @@ -96,7 +96,7 @@ Kubespray fournit des playbooks supplémentaires qui permettent de gérer votre ### Mise à l'échelle du cluster -Vous pouvez ajouter des noeuds à votre cluter en exécutant le playbook `scale`. Pour plus d'informations se référer à [Adding nodes](https://github.com/kubernetes-incubator/kubespray/blob/master/docs/getting-started.md#adding-nodes). +Vous pouvez ajouter des noeuds à votre cluster en exécutant le playbook `scale`. Pour plus d'informations se référer à [Adding nodes](https://github.com/kubernetes-incubator/kubespray/blob/master/docs/getting-started.md#adding-nodes). vous pouvez retirer des noeuds de votre cluster en exécutant le playbook `remove-node`. Se référer à [Remove nodes](https://github.com/kubernetes-incubator/kubespray/blob/master/docs/getting-started.md#remove-nodes). ### Mise à jour du cluster From fa112da3781165fd64b36e735db313acaea923d2 Mon Sep 17 00:00:00 2001 From: LFA Date: Tue, 25 Feb 2020 09:50:48 +0100 Subject: [PATCH 083/111] fix typo (#19298) --- content/fr/docs/reference/glossary/kube-controller-manager.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/fr/docs/reference/glossary/kube-controller-manager.md b/content/fr/docs/reference/glossary/kube-controller-manager.md index 6481dd7d4e..2d45431e45 100755 --- a/content/fr/docs/reference/glossary/kube-controller-manager.md +++ b/content/fr/docs/reference/glossary/kube-controller-manager.md @@ -16,4 +16,4 @@ tags: Logiquement, chaque {{< glossary_tooltip text="contrôleur" term_id="controller" >}} est un processus à part mais, -pour réduire la compléxité, les contrôleurs sont tous compilés dans un seul binaire et s'exécutent dans un seul processus. +pour réduire la complexité, les contrôleurs sont tous compilés dans un seul binaire et s'exécutent dans un seul processus. From d93595e7fc9a2fbf8975cd9ade76cac89dbb8bee Mon Sep 17 00:00:00 2001 From: Yan Wei Date: Tue, 25 Feb 2020 03:12:48 -0600 Subject: [PATCH 084/111] Add a missing '-' to names.md (#18115) Add a missing '-' to names.md --- content/zh/docs/concepts/overview/working-with-objects/names.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/zh/docs/concepts/overview/working-with-objects/names.md b/content/zh/docs/concepts/overview/working-with-objects/names.md index cff7f34e4a..1b139eae76 100644 --- a/content/zh/docs/concepts/overview/working-with-objects/names.md +++ b/content/zh/docs/concepts/overview/working-with-objects/names.md @@ -45,7 +45,7 @@ By convention, the names of Kubernetes resources should be up to maximum length For example, here’s the configuration file with a Pod name as `nginx-demo` and a Container name as `nginx`: --> -例如,下面是一个配置文件,Pod 名为 `nginx demo`,容器名为 `nginx`: +例如,下面是一个配置文件,Pod 名为 `nginx-demo`,容器名为 `nginx`: ```yaml apiVersion: v1 From 3ecfc9f47fc99ec983bbaed54a36dcc32f1a9237 Mon Sep 17 00:00:00 2001 From: Sascha Grunert Date: Tue, 25 Feb 2020 14:42:49 +0100 Subject: [PATCH 085/111] Fix wrong CHANGELOG locations (#19089) We prefixed the CHANGELOG path in k/k with `CHANGELOG/`, which should reflect every part of the website as well. Signed-off-by: Sascha Grunert --- content/de/docs/reference/kubectl/cheatsheet.md | 2 +- .../tasks/administer-cluster/kubeadm/kubeadm-upgrade.md | 2 +- content/fr/docs/reference/kubectl/cheatsheet.md | 2 +- content/ja/docs/reference/kubectl/cheatsheet.md | 2 +- content/ko/docs/reference/kubectl/cheatsheet.md | 2 +- content/vi/docs/reference/kubectl/cheatsheet.md | 2 +- content/zh/docs/reference/kubectl/cheatsheet.md | 4 ++-- .../tasks/administer-cluster/kubeadm/kubeadm-upgrade.md | 6 +++--- layouts/shortcodes/latest-release-notes.html | 3 +++ 9 files changed, 14 insertions(+), 11 deletions(-) create mode 100644 layouts/shortcodes/latest-release-notes.html diff --git a/content/de/docs/reference/kubectl/cheatsheet.md b/content/de/docs/reference/kubectl/cheatsheet.md index 507fbbd50d..c68fc183b5 100644 --- a/content/de/docs/reference/kubectl/cheatsheet.md +++ b/content/de/docs/reference/kubectl/cheatsheet.md @@ -180,7 +180,7 @@ kubectl get events --sort-by=.metadata.creationTimestamp ## Ressourcen aktualisieren -Ab Version 1.11 ist das `rolling-update` veraltet (Lesen Sie [CHANGELOG-1.11.md](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.11.md) für weitere Informationen), verwenden Sie stattdessen `rollout`. +Ab Version 1.11 ist das `rolling-update` veraltet (Lesen Sie [CHANGELOG-1.11.md](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.11.md) für weitere Informationen), verwenden Sie stattdessen `rollout`. ```bash kubectl set image deployment/frontend www=image:v2 # Fortlaufende Aktualisierung der "www" Container der "Frontend"-Bereitstellung, Aktualisierung des Images diff --git a/content/en/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade.md b/content/en/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade.md index 73878bbd9d..ce898371fb 100644 --- a/content/en/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade.md +++ b/content/en/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade.md @@ -30,7 +30,7 @@ The upgrade workflow at high level is the following: - You need to have a kubeadm Kubernetes cluster running version 1.16.0 or later. - [Swap must be disabled](https://serverfault.com/questions/684771/best-way-to-disable-swap-in-linux). - The cluster should use a static control plane and etcd pods or external etcd. -- Make sure you read the [release notes](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.17.md) carefully. +- Make sure you read the [release notes]({{< latest-release-notes >}}) carefully. - Make sure to back up any important components, such as app-level state stored in a database. `kubeadm upgrade` does not touch your workloads, only components internal to Kubernetes, but backups are always a best practice. diff --git a/content/fr/docs/reference/kubectl/cheatsheet.md b/content/fr/docs/reference/kubectl/cheatsheet.md index f9ced10b4b..0c320717a2 100644 --- a/content/fr/docs/reference/kubectl/cheatsheet.md +++ b/content/fr/docs/reference/kubectl/cheatsheet.md @@ -197,7 +197,7 @@ kubectl get events --sort-by=.metadata.creationTimestamp ## Mise à jour de ressources -Depuis la version 1.11, `rolling-update` a été déprécié (voir [CHANGELOG-1.11.md](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.11.md)), utilisez plutôt `rollout`. +Depuis la version 1.11, `rolling-update` a été déprécié (voir [CHANGELOG-1.11.md](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.11.md)), utilisez plutôt `rollout`. ```bash kubectl set image deployment/frontend www=image:v2 # Rolling update du conteneur "www" du déploiement "frontend", par mise à jour de son image diff --git a/content/ja/docs/reference/kubectl/cheatsheet.md b/content/ja/docs/reference/kubectl/cheatsheet.md index 044e16bffa..9380b50c07 100644 --- a/content/ja/docs/reference/kubectl/cheatsheet.md +++ b/content/ja/docs/reference/kubectl/cheatsheet.md @@ -202,7 +202,7 @@ kubectl get events --sort-by=.metadata.creationTimestamp ## リソースのアップデート -version 1.11で`rolling-update`は廃止されました、代わりに`rollout`コマンドをお使いください(詳しくはこちらをご覧ください [CHANGELOG-1.11.md](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.11.md))。 +version 1.11で`rolling-update`は廃止されました、代わりに`rollout`コマンドをお使いください(詳しくはこちらをご覧ください [CHANGELOG-1.11.md](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.11.md))。 ```bash kubectl set image deployment/frontend www=image:v2 # frontend Deploymentのwwwコンテナイメージをv2にローリングアップデートします diff --git a/content/ko/docs/reference/kubectl/cheatsheet.md b/content/ko/docs/reference/kubectl/cheatsheet.md index 3ea2a1e60b..071669a6c8 100644 --- a/content/ko/docs/reference/kubectl/cheatsheet.md +++ b/content/ko/docs/reference/kubectl/cheatsheet.md @@ -198,7 +198,7 @@ kubectl diff -f ./my-manifest.yaml ## 리소스 업데이트 -1.11 버전에서 `rolling-update`는 사용 중단(deprecated)되었다. ([CHANGELOG-1.11.md](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.11.md) 참고) 대신 `rollout`를 사용한다. +1.11 버전에서 `rolling-update`는 사용 중단(deprecated)되었다. ([CHANGELOG-1.11.md](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.11.md) 참고) 대신 `rollout`를 사용한다. ```bash kubectl set image deployment/frontend www=image:v2 # "frontend" 디플로이먼트의 "www" 컨테이너 이미지를 업데이트하는 롤링 업데이트 diff --git a/content/vi/docs/reference/kubectl/cheatsheet.md b/content/vi/docs/reference/kubectl/cheatsheet.md index 1455b0e892..261b45f824 100644 --- a/content/vi/docs/reference/kubectl/cheatsheet.md +++ b/content/vi/docs/reference/kubectl/cheatsheet.md @@ -197,7 +197,7 @@ kubectl get events --sort-by=.metadata.creationTimestamp ## Cập nhật các tài nguyên -Theo như phiên bản 1.11, `rolling-update` đã không còn được dùng nữa (xem [CHANGELOG-1.11.md](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.11.md)), sử dụng `rollout` thay thế. +Theo như phiên bản 1.11, `rolling-update` đã không còn được dùng nữa (xem [CHANGELOG-1.11.md](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.11.md)), sử dụng `rollout` thay thế. ```bash kubectl set image deployment/frontend www=image:v2 # Cập nhận container "www" của deployment "frontend", cập nhật image diff --git a/content/zh/docs/reference/kubectl/cheatsheet.md b/content/zh/docs/reference/kubectl/cheatsheet.md index 75b7c2f7be..43ded7f976 100644 --- a/content/zh/docs/reference/kubectl/cheatsheet.md +++ b/content/zh/docs/reference/kubectl/cheatsheet.md @@ -358,8 +358,8 @@ kubectl get events --sort-by=.metadata.creationTimestamp ## 更新资源 - -从版本 1.11 开始,`rolling-update` 已被弃用(参见 [CHANGELOG-1.11.md](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.11.md)),请使用 `rollout` 代替。 + +从版本 1.11 开始,`rolling-update` 已被弃用(参见 [CHANGELOG-1.11.md](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.11.md)),请使用 `rollout` 代替。 - 您需要有一个由 `kubeadm` 创建并运行着 1.16.0 或更高版本的 Kubernetes 集群。 - [禁用 Swap](https://serverfault.com/questions/684771/best-way-to-disable-swap-in-linux)。 - 集群应使用静态的控制平面和 etcd pod 或者 外部 etcd。 -- 务必仔细认真阅读[发行说明](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.16.md)。 +- 务必仔细认真阅读[发行说明]({{< latest-release-notes >}})。 - 务必备份所有重要组件,例如存储在数据库中应用层面的状态。 `kubeadm upgrade` 不会影响您的工作负载,只会涉及 Kubernetes 内部的组件,但备份终究是好的。 @@ -666,4 +666,4 @@ To recover from a bad state, you can also run `kubeadm upgrade --force` without `kubeadm upgrade node experimental-control-plane` 在其他控制平面节点上执行以下操作: - 从集群中获取 kubeadm `ClusterConfiguration`。 - 可选地备份 kube-apiserver 证书。 -- 升级控制平面组件的静态 Pod 清单。 \ No newline at end of file +- 升级控制平面组件的静态 Pod 清单。 diff --git a/layouts/shortcodes/latest-release-notes.html b/layouts/shortcodes/latest-release-notes.html new file mode 100644 index 0000000000..3f380408ee --- /dev/null +++ b/layouts/shortcodes/latest-release-notes.html @@ -0,0 +1,3 @@ +{{- $latestVersion := site.Params.latest }} +{{- $latestReleaseNotes := print "https://git.k8s.io/kubernetes/CHANGELOG/CHANGELOG-" (replace $latestVersion "v" "") ".md" }} +{{- $latestReleaseNotes }} From 119ba0d87ab852ec92484462ad2103650177321b Mon Sep 17 00:00:00 2001 From: Victor Shinya Date: Tue, 25 Feb 2020 11:42:48 -0300 Subject: [PATCH 086/111] Remove IBM course (#18836) Since January 2020, IBM removed all microservice courses and specialization on Coursera. --- content/en/docs/tutorials/online-training/overview.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/content/en/docs/tutorials/online-training/overview.md b/content/en/docs/tutorials/online-training/overview.md index 7112a8b3bf..e76b22481a 100644 --- a/content/en/docs/tutorials/online-training/overview.md +++ b/content/en/docs/tutorials/online-training/overview.md @@ -39,8 +39,6 @@ Here are some of the sites that offer online training for Kubernetes: * [Hands-on Introduction to Kubernetes (Instruqt)](https://play.instruqt.com/public/topics/getting-started-with-kubernetes) -* [IBM Cloud: Deploying Microservices with Kubernetes (Coursera)](https://www.coursera.org/learn/deploy-micro-kube-ibm-cloud) - * [Introduction to Kubernetes (edX)](https://www.edx.org/course/introduction-kubernetes-linuxfoundationx-lfs158x) * [Kubernetes Essentials with Hands-On Labs (Linux Academy)] (https://linuxacademy.com/linux/training/course/name/kubernetes-essentials) From 3f020e5f5c47176511fbaa90950a9870174a510f Mon Sep 17 00:00:00 2001 From: Art Date: Tue, 25 Feb 2020 11:48:49 -0500 Subject: [PATCH 087/111] Update IBM Cloud registry for IAM (#19303) Updates the topic to describe how to use IAM to authorize clusters to pull images from registry. --- content/en/docs/concepts/containers/images.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/content/en/docs/concepts/containers/images.md b/content/en/docs/concepts/containers/images.md index e22a742d36..94f69ba6af 100644 --- a/content/en/docs/concepts/containers/images.md +++ b/content/en/docs/concepts/containers/images.md @@ -67,6 +67,7 @@ Credentials can be provided in several ways: - use IAM roles and policies to control access to OCIR repositories - Using Azure Container Registry (ACR) - Using IBM Cloud Container Registry + - use IAM roles and policies to grant access to IBM Cloud Container Registry - Configuring Nodes to Authenticate to a Private Registry - all pods can read any configured private registries - requires node configuration by cluster administrator @@ -148,11 +149,11 @@ Once you have those variables filled in you can [configure a Kubernetes Secret and use it to deploy a Pod](/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod). ### Using IBM Cloud Container Registry -IBM Cloud Container Registry provides a multi-tenant private image registry that you can use to safely store and share your Docker images. By default, images in your private registry are scanned by the integrated Vulnerability Advisor to detect security issues and potential vulnerabilities. Users in your IBM Cloud account can access your images, or you can create a token to grant access to registry namespaces. +IBM Cloud Container Registry provides a multi-tenant private image registry that you can use to safely store and share your images. By default, images in your private registry are scanned by the integrated Vulnerability Advisor to detect security issues and potential vulnerabilities. Users in your IBM Cloud account can access your images, or you can use IAM roles and policies to grant access to IBM Cloud Container Registry namespaces. -To install the IBM Cloud Container Registry CLI plug-in and create a namespace for your images, see [Getting started with IBM Cloud Container Registry](https://cloud.ibm.com/docs/services/Registry?topic=registry-getting-started). +To install the IBM Cloud Container Registry CLI plug-in and create a namespace for your images, see [Getting started with IBM Cloud Container Registry](https://cloud.ibm.com/docs/Registry?topic=registry-getting-started). -You can use the IBM Cloud Container Registry to deploy containers from [IBM Cloud public images](https://cloud.ibm.com/docs/services/Registry?topic=registry-public_images) and your private images into the `default` namespace of your IBM Cloud Kubernetes Service cluster. To deploy a container into other namespaces, or to use an image from a different IBM Cloud Container Registry region or IBM Cloud account, create a Kubernetes `imagePullSecret`. For more information, see [Building containers from images](https://cloud.ibm.com/docs/containers?topic=containers-images). +If you are using the same account and region, you can deploy images that are stored in IBM Cloud Container Registry into the default namespace of your IBM Cloud Kubernetes Service cluster without any additional configuration, see [Building containers from images](https://cloud.ibm.com/docs/containers?topic=containers-images). For other configuration options, see [Understanding how to authorize your cluster to pull images from a registry](https://cloud.ibm.com/docs/containers?topic=containers-registry#cluster_registry_auth). ### Configuring Nodes to Authenticate to a Private Registry From 03f5e9f846e1fc52217d7ad1dfeac33e347f3d0c Mon Sep 17 00:00:00 2001 From: chentanjun <2799194073@qq.com> Date: Wed, 26 Feb 2020 11:08:26 +0800 Subject: [PATCH 088/111] update zh-trabns content/zh/docs/concepts/services-networking/ingress-controllers.md (#19130) --- .../ingress-controllers.md | 249 ++++++++++-------- 1 file changed, 133 insertions(+), 116 deletions(-) diff --git a/content/zh/docs/concepts/services-networking/ingress-controllers.md b/content/zh/docs/concepts/services-networking/ingress-controllers.md index b427403eba..c6bdeccd00 100644 --- a/content/zh/docs/concepts/services-networking/ingress-controllers.md +++ b/content/zh/docs/concepts/services-networking/ingress-controllers.md @@ -1,116 +1,133 @@ ---- -title: Ingress 控制器 -content_template: templates/concept -weight: 40 ---- - -{{% capture overview %}} - - - -为了让 Ingress 资源工作,集群必须有一个正在运行的 Ingress 控制器。 - -与其他类型的控制器不同,它们是作为 `kube-controller-manager` 二进制文件的一部分运行的,而 Ingress 控制器不是随集群自动启动的。 -通过此页面可选择最适合您的集群的 ingress 控制器实现。 - -Kubernetes 作为一个项目,目前支持和维护 [GCE](https://git.k8s.io/ingress-gce/README.md) 和 - [nginx](https://git.k8s.io/ingress-nginx/README.md) 控制器。 - -{{% /capture %}} - -{{% capture body %}} - - -## 其他控制器 - -* [Ambassador](https://www.getambassador.io/) API 网关, 一个基于 [Envoy](https://www.envoyproxy.io) 的 ingress - 控制器,有着来自 [Datawire](https://www.datawire.io/) [社区](https://www.getambassador.io/docs)或[商业](https://www.getambassador.io/pro/)的支持。 -* [AppsCode Inc.](https://appscode.com) 为最广泛使用的基于 [HAProxy](http://www.haproxy.org/) 的 ingress 控制器 [Voyager](https://appscode.com/products/voyager) 提供支持和维护. -* [Contour](https://projectcontour.io/) 是一个基于 [Envoy](https://www.envoyproxy.io/) 的 ingress 控制器,它由 VMware 提供和支持。 -* Citrix 为其硬件(MPX),虚拟化(VPX)和 [免费容器化 (CPX) ADC](https://www.citrix.com/products/citrix-adc/cpx-express.html) 提供了一个 [Ingress 控制器](https://github.com/citrix/citrix-k8s-ingress-controller),用于[裸金属](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/deployment/baremetal)和[云](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/deployment)部署。 -* F5 Networks 为 [用于 Kubernetes 的 F5 BIG-IP 控制器](http://clouddocs.f5.com/products/connectors/k8s-bigip-ctlr/latest)提供[支持和维护](https://support.f5.com/csp/article/K86859508)。 -* [Gloo](https://gloo.solo.io) 是一个开源的基于 [Envoy](https://www.envoyproxy.io) 的 ingress 控制器,它提供了 API 网关功能,有着来自 [solo.io](https://www.solo.io) 的企业级支持。 -* [HAProxy Technologies](https://www.haproxy.com/) 为 [HAProxy Ingress Controller for Kubernetes](https://github.com/haproxytech/kubernetes-ingress). See the [official documentation](https://www.haproxy.com/documentation/hapee/1-9r1/traffic-management/kubernetes-ingress-controller/) 提供支持和运维服务。 -* 基于 [Istio](https://istio.io/) 的 ingress 控制器[控制 Ingress 流量](https://istio.io/docs/tasks/traffic-management/ingress/)。 -* [Kong](https://konghq.com/) 为[用于 Kubernetes 的 Kong Ingress 控制器](https://github.com/Kong/kubernetes-ingress-controller) 提供[社区](https://discuss.konghq.com/c/kubernetes)或[商业](https://konghq.com/kong-enterprise/)支持和维护。 -* [NGINX, Inc.](https://www.nginx.com/) 为[用于 Kubernetes 的 NGINX Ingress 控制器](https://www.nginx.com/products/nginx/kubernetes-ingress-controller)提供支持和维护。 -* [Skipper](https://opensource.zalando.com/skipper/kubernetes/ingress-controller/) HTTP路由器和反向代理,用于服务组合,包括诸如Kubernetes Ingress之类的用例,被设计为用于构建自定义代理的库。 -* [Traefik](https://github.com/containous/traefik) 是一个全功能的 ingress 控制器 - ([Let's Encrypt](https://letsencrypt.org),secrets,http2,websocket),并且它也有来自 [Containous](https://containo.us/services) 的商业支持。 - - -## 使用多个 Ingress 控制器 - -你可以在集群中部署[任意数量的 ingress 控制器](https://git.k8s.io/ingress-nginx/docs/user-guide/multiple-ingress.md#multiple-ingress-controllers)。 -创建 ingress 时,应该使用适当的 -[`ingress.class`](https://git.k8s.io/ingress-gce/docs/faq/README.md#how-do-i-run-multiple-ingress-controllers-in-the-same-cluster) 注解每个 ingress -以表明在集群中如果有多个 ingress 控制器时,应该使用哪个 ingress 控制器。 - -如果不定义 `ingress.class`,云提供商可能使用默认的 ingress 控制器。 - -理想情况下,所有 ingress 控制器都应满足此规范,但各种 ingress 控制器的操作略有不同。 - -{{< note >}} - -确保您查看了 ingress 控制器的文档,以了解选择它的注意事项。 -{{< /note >}} - -{{% /capture %}} - -{{% capture whatsnext %}} - -* 了解更多关于 [Ingress](/docs/concepts/services-networking/ingress/)。 -* [在 Minikube 上使用 NGINX 控制器安装 Ingress](/docs/tasks/access-application-cluster/ingress-minikube)。 -{{% /capture %}} +--- +title: Ingress 控制器 +content_template: templates/concept +weight: 40 +--- + + + +{{% capture overview %}} + + + +为了让 Ingress 资源工作,集群必须有一个正在运行的 Ingress 控制器。 + +与作为 `kube-controller-manager` 可执行文件的一部分运行的其他类型的控制器不同,Ingress 控制器不是随集群自动启动的。 +基于此页面,您可选择最适合您的集群的 ingress 控制器实现。 + +Kubernetes 作为一个项目,目前支持和维护 [GCE](https://git.k8s.io/ingress-gce/README.md) +和 [nginx](https://git.k8s.io/ingress-nginx/README.md) 控制器。 + +{{% /capture %}} + +{{% capture body %}} + + +## 其他控制器 + + +* [AKS 应用程序网关 Ingress 控制器]使用 [Azure 应用程序网关](https://docs.microsoft.com/azure/application-gateway/overview)启用[AKS 集群](https://docs.microsoft.com/azure/aks/kubernetes-walkthrough-portal) ingress。 +* [Ambassador](https://www.getambassador.io/) API 网关, 一个基于 [Envoy](https://www.envoyproxy.io) 的 ingress + 控制器,有着来自[社区](https://www.getambassador.io/docs) 的支持和来自 [Datawire](https://www.datawire.io/) 的[商业](https://www.getambassador.io/pro/) 支持。 +* [AppsCode Inc.](https://appscode.com) 为最广泛使用的基于 [HAProxy](http://www.haproxy.org/) 的 ingress 控制器 [Voyager](https://appscode.com/products/voyager) 提供支持和维护。 +* [AWS ALB Ingress 控制器](https://github.com/kubernetes-sigs/aws-alb-ingress-controller)通过 [AWS 应用 Load Balancer](https://aws.amazon.com/elasticloadbalancing/) 启用 ingress。 +* [Contour](https://projectcontour.io/) 是一个基于 [Envoy](https://www.envoyproxy.io/) 的 ingress 控制器,它由 VMware 提供和支持。 +* Citrix 为其硬件(MPX),虚拟化(VPX)和 [免费容器化 (CPX) ADC](https://www.citrix.com/products/citrix-adc/cpx-express.html) 提供了一个 [Ingress 控制器](https://github.com/citrix/citrix-k8s-ingress-controller),用于[裸金属](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/deployment/baremetal)和[云](https://github.com/citrix/citrix-k8s-ingress-controller/tree/master/deployment)部署。 +* F5 Networks 为 [用于 Kubernetes 的 F5 BIG-IP 控制器](http://clouddocs.f5.com/products/connectors/k8s-bigip-ctlr/latest)提供[支持和维护](https://support.f5.com/csp/article/K86859508)。 +* [Gloo](https://gloo.solo.io) 是一个开源的基于 [Envoy](https://www.envoyproxy.io) 的 ingress 控制器,它提供了 API 网关功能,有着来自 [solo.io](https://www.solo.io) 的企业级支持。 +* [HAProxy Ingress](https://haproxy-ingress.github.io) 是 HAProxy 高度可定制的、由社区驱动的 Ingress 控制器。 +* [HAProxy Technologies](https://www.haproxy.com/) 为[用于 Kubernetes 的 HAProxy Ingress 控制器](https://github.com/haproxytech/kubernetes-ingress) 提供支持和维护。具体信息请参考[官方文档](https://www.haproxy.com/documentation/hapee/1-9r1/traffic-management/kubernetes-ingress-controller/)。 +* 基于 [Istio](https://istio.io/) 的 ingress 控制器[控制 Ingress 流量](https://istio.io/docs/tasks/traffic-management/ingress/)。 +* [Kong](https://konghq.com/) 为[用于 Kubernetes 的 Kong Ingress 控制器](https://github.com/Kong/kubernetes-ingress-controller) 提供[社区](https://discuss.konghq.com/c/kubernetes)或[商业](https://konghq.com/kong-enterprise/)支持和维护。 +* [NGINX, Inc.](https://www.nginx.com/) 为[用于 Kubernetes 的 NGINX Ingress 控制器](https://www.nginx.com/products/nginx/kubernetes-ingress-controller)提供支持和维护。 +* [Skipper](https://opensource.zalando.com/skipper/kubernetes/ingress-controller/) HTTP 路由器和反向代理,用于服务组合,包括诸如 Kubernetes Ingress 之类的用例,被设计为用于构建自定义代理的库。 +* [Traefik](https://github.com/containous/traefik) 是一个全功能的 ingress 控制器 + ([Let's Encrypt](https://letsencrypt.org),secrets,http2,websocket),并且它也有来自 [Containous](https://containo.us/services) 的商业支持。 + + +## 使用多个 Ingress 控制器 + + + +你可以在集群中部署[任意数量的 ingress 控制器](https://git.k8s.io/ingress-nginx/docs/user-guide/multiple-ingress.md#multiple-ingress-controllers)。 +创建 ingress 时,应该使用适当的 [`ingress.class`](https://git.k8s.io/ingress-gce/docs/faq/README.md#how-do-i-run-multiple-ingress-controllers-in-the-same-cluster) 注解每个 ingress +以表明在集群中如果有多个 ingress 控制器时,应该使用哪个 ingress 控制器。 + +如果不定义 `ingress.class`,云提供商可能使用默认的 ingress 控制器。 + +理想情况下,所有 ingress 控制器都应满足此规范,但各种 ingress 控制器的操作略有不同。 + + +{{< note >}} +确保您查看了 ingress 控制器的文档,以了解选择它的注意事项。 +{{< /note >}} + +{{% /capture %}} + +{{% capture whatsnext %}} + +* 进一步了解 [Ingress](/docs/concepts/services-networking/ingress/)。 +* [在 Minikube 上使用 NGINX 控制器安装 Ingress](/docs/tasks/access-application-cluster/ingress-minikube)。 +{{% /capture %}} From 88de2a0586d41174ec51c46cd1dc1c84747f8d95 Mon Sep 17 00:00:00 2001 From: Tobias Liese <56112387+SR-Lut3t1um@users.noreply.github.com> Date: Wed, 26 Feb 2020 11:48:25 +0100 Subject: [PATCH 089/111] fixed typo (#19202) --- content/de/docs/concepts/containers/images.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/de/docs/concepts/containers/images.md b/content/de/docs/concepts/containers/images.md index 98e012640c..8f41b0c2e1 100644 --- a/content/de/docs/concepts/containers/images.md +++ b/content/de/docs/concepts/containers/images.md @@ -96,7 +96,7 @@ Das Google service Konto der Instanz hat einen `https://www.googleapis.com/auth/ Kubernetes eine native Unterstützung für die [Amazon Elastic Container Registry](https://aws.amazon.com/ecr/) wenn Knoten AWS EC2 Instanzen sind. -Es muss einfah nur der komplette Image Name (z.B. `ACCOUNT.dkr.ecr.REGION.amazonaws.com/imagename:tag`) in der Pod - Definition genutzt werden. +Es muss einfach nur der komplette Image Name (z.B. `ACCOUNT.dkr.ecr.REGION.amazonaws.com/imagename:tag`) in der Pod - Definition genutzt werden. Alle Benutzer eines Clusters die Pods erstellen dürfen können dann jedes der Images in der ECR Registry zum Ausführen von Pods nutzen. From f75df43c74ed1e2acf0faaaee40579c5c464f424 Mon Sep 17 00:00:00 2001 From: Taylor Dolezal Date: Wed, 26 Feb 2020 23:21:19 -0800 Subject: [PATCH 090/111] Add onlydole to EN sections, remove duplicate entry (#19332) --- OWNERS_ALIASES | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES index bf898fed46..291db36bf2 100644 --- a/OWNERS_ALIASES +++ b/OWNERS_ALIASES @@ -30,7 +30,6 @@ aliases: - onlydole - parispittman - vonguard - - onlydole sig-docs-de-owners: # Admins for German content - bene2k1 - mkorbi @@ -48,6 +47,7 @@ aliases: - kbarnard10 - kbhawkey - makoscafee + - onlydole - Rajakavitha1 - sftim - steveperry-53 @@ -64,6 +64,7 @@ aliases: - kbarnard10 - kbhawkey - makoscafee + - onlydole - rajakavitha1 - sftim - steveperry-53 From 91333c47e5ec70c69deb13d3fac19573c3925a2f Mon Sep 17 00:00:00 2001 From: wwgfhf <51694849+wwgfhf@users.noreply.github.com> Date: Thu, 27 Feb 2020 16:29:21 +0800 Subject: [PATCH 091/111] Update apparmor.md (#19322) --- content/zh/docs/tutorials/clusters/apparmor.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/zh/docs/tutorials/clusters/apparmor.md b/content/zh/docs/tutorials/clusters/apparmor.md index 8bb34517f5..627a52ede9 100644 --- a/content/zh/docs/tutorials/clusters/apparmor.md +++ b/content/zh/docs/tutorials/clusters/apparmor.md @@ -424,7 +424,7 @@ Kubernetes 目前不提供任何本地机制来将 AppArmor 配置文件加载 * By copying the profiles to each node and loading them through SSH, as demonstrated in the [Example](#example). --> * 通过在每个节点上运行 Pod 的[DaemonSet](/docs/concepts/workloads/controllers/daemonset/)确保加载了正确的配置文件。可以找到一个示例实现[这里](https://git.k8s.io/kubernetes/test/images/apparmor-loader)。 -* 在节点初始化时,使用节点初始化脚本(例如 Salt 、Ansible 等)或图像。 +* 在节点初始化时,使用节点初始化脚本(例如 Salt 、Ansible 等)或镜像。 * 通过将配置文件复制到每个节点并通过 SSH 加载它们,如[示例](#example)。 -[장치 플러그인](/docs/concepts/extend-kubernetes/compute-storage-net/device-plugins/)은 쿠버네티스에서 동작하는 컨테이너이며 공급 업체 고유의 리소스에 대한 액세스를 제공한다. 장치 플로그인은 해당 리소스를 {{< glossary_tooltip term_id="kubelet" >}}에 알린다. 장치 플러그인은 사용자 정의 쿠버네티스 코드를 작성하는 대신 수동으로 또는 {{< glossary_tooltip text="데몬셋" term_id="daemonset" >}}으로도 디플로이 가능하다. +장치 플러그인은 {{< glossary_tooltip term_id="kubelet" text="kubelet" >}}에 +리소스를 알리기에 워크로드 파드는 해당 파드가 실행중인 +노드와 관련된 하드웨어 기능에 접근할 수 있다. +장치 플러그인을 {{< glossary_tooltip term_id="daemonset" >}}으로 배포하거나, +각 대상 노드에 직접 장치 플러그인 소프트웨어를 설치할 수 있다. + +[장치 플러그인](/docs/concepts/extend-kubernetes/compute-storage-net/device-plugins/) +의 더 자세한 정보를 +본다 diff --git a/content/ko/docs/reference/kubectl/cheatsheet.md b/content/ko/docs/reference/kubectl/cheatsheet.md index 071669a6c8..ccac6c32d1 100644 --- a/content/ko/docs/reference/kubectl/cheatsheet.md +++ b/content/ko/docs/reference/kubectl/cheatsheet.md @@ -140,7 +140,7 @@ EOF # 기본 출력을 위한 Get 커맨드 kubectl get services # 네임스페이스 내 모든 서비스의 목록 조회 kubectl get pods --all-namespaces # 모든 네임스페이스 내 모든 파드의 목록 조회 -kubectl get pods -o wide # 네임스페이스 내 모든 파드의 상세 목록 조회 +kubectl get pods -o wide # 해당하는 네임스페이스 내 모든 파드의 상세 목록 조회 kubectl get deployment my-dep # 특정 디플로이먼트의 목록 조회 kubectl get pods # 네임스페이스 내 모든 파드의 목록 조회 kubectl get pod my-pod -o yaml # 파드의 YAML 조회 @@ -156,9 +156,8 @@ kubectl get services --sort-by=.metadata.name # 재시작 횟수로 정렬된 파드의 목록 조회 kubectl get pods --sort-by='.status.containerStatuses[0].restartCount' -# test 네임스페이스를 가지는 PersistentVolumes을 용량별로 정렬해서 조회 - -kubectl get pv -n test --sort-by=.spec.capacity.storage +# PersistentVolumes을 용량별로 정렬해서 조회 +kubectl get pv --sort-by=.spec.capacity.storage # app=cassandra 레이블을 가진 모든 파드의 레이블 버전 조회 kubectl get pods --selector=app=cassandra -o \ diff --git a/content/ko/docs/reference/using-api/client-libraries.md b/content/ko/docs/reference/using-api/client-libraries.md index f02188813b..3cc93f7c7f 100644 --- a/content/ko/docs/reference/using-api/client-libraries.md +++ b/content/ko/docs/reference/using-api/client-libraries.md @@ -69,6 +69,7 @@ Machinery](https://github.com/kubernetes/community/tree/master/sig-api-machinery | dotNet | [github.com/tonnyeremin/kubernetes_gen](https://github.com/tonnyeremin/kubernetes_gen) | | DotNet (RestSharp) | [github.com/masroorhasan/Kubernetes.DotNet](https://github.com/masroorhasan/Kubernetes.DotNet) | | Elixir | [github.com/obmarg/kazan](https://github.com/obmarg/kazan/) | +| Elixir | [github.com/coryodaniel/k8s](https://github.com/coryodaniel/k8s) | | Haskell | [github.com/kubernetes-client/haskell](https://github.com/kubernetes-client/haskell) | {{% /capture %}} diff --git a/content/ko/docs/setup/_index.md b/content/ko/docs/setup/_index.md index 668684fa03..0ece7e3661 100644 --- a/content/ko/docs/setup/_index.md +++ b/content/ko/docs/setup/_index.md @@ -37,7 +37,7 @@ card: |커뮤니티 |생태계 | | ------------ | -------- | | [Minikube](/docs/setup/learning-environment/minikube/) | [CDK on LXD](https://www.ubuntu.com/kubernetes/docs/install-local) | -| [kind (Kubernetes IN Docker)](https://github.com/kubernetes-sigs/kind) | [Docker Desktop](https://www.docker.com/products/docker-desktop)| +| [kind (Kubernetes IN Docker)](/docs/setup/learning-environment/kind/) | [Docker Desktop](https://www.docker.com/products/docker-desktop)| | | [Minishift](https://docs.okd.io/latest/minishift/)| | | [MicroK8s](https://microk8s.io/)| | | [IBM Cloud Private-CE (Community Edition)](https://github.com/IBM/deploy-ibm-cloud-private) | diff --git a/content/ko/docs/setup/learning-environment/minikube.md b/content/ko/docs/setup/learning-environment/minikube.md index d66ada6ea8..5bea0d3d9b 100644 --- a/content/ko/docs/setup/learning-environment/minikube.md +++ b/content/ko/docs/setup/learning-environment/minikube.md @@ -200,7 +200,11 @@ minikube start --vm-driver= * hyperv ([드라이버 설치](https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#hyperv-driver)) 다음 IP는 동적이며 변경할 수 있다. `minikube ip`로 알아낼 수 있다. * vmware ([드라이버 설치](https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#vmware-unified-driver)) (VMware unified driver) -* none (쿠버네티스 컴포넌트를 VM이 아닌 호스트 상에서 구동한다. 개인용 워크스테이션에서 none 드라이버를 사용하는 것을 권장하지 않는다. 이 드라이버를 사용하려면 도커와 리눅스 환경이 필요하다.([도커 설치](https://docs.docker.com/install/linux/docker-ce/ubuntu/))) +* none (쿠버네티스 컴포넌트를 가상 머신이 아닌 호스트 상에서 구동한다. 리눅스를 실행중이어야 하고, {{< glossary_tooltip term_id="docker" >}}가 설치되어야 한다.) + +{{< caution >}} +`none` 드라이버를 사용한다면 일부 쿠버네티스 컴포넌트는 Minikube 환경 외부에 있는 부작용이 있는 권한을 가진 컨테이너로 실행된다. 이런 부작용은 개인용 워크스테이션에는 `none` 드라이버가 권장하지 않는 것을 의미 한다. +{{< /caution >}} #### 대안적인 컨테이너 런타임 상에서 클러스터 시작하기 Minikube를 다음의 컨테이너 런타임에서 기동할 수 있다. diff --git a/content/ko/docs/setup/production-environment/container-runtimes.md b/content/ko/docs/setup/production-environment/container-runtimes.md index c83a13327a..e20fe5fd0a 100644 --- a/content/ko/docs/setup/production-environment/container-runtimes.md +++ b/content/ko/docs/setup/production-environment/container-runtimes.md @@ -73,7 +73,7 @@ kubelet을 재시작 하는 것은 에러를 해결할 수 없을 것이다. ## 리포지터리 설정 ### apt가 HTTPS 리포지터리를 사용할 수 있도록 해주는 패키지 설치 apt-get update && apt-get install -y \ - apt-transport-https ca-certificates curl software-properties-common + apt-transport-https ca-certificates curl software-properties-common gnupg2 ### Docker의 공식 GPG 키 추가 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - @@ -160,6 +160,11 @@ systemctl restart docker 시스템에 CRI-O를 설치하기 위해서 다음의 커맨드를 사용한다. +{{< note >}} +CRI-O 메이저와 마이너 버전은 쿠버네티스 메이저와 마이너 버전이 일치해야 한다. +더 자세한 정보는 [CRI-O 호환 매트릭스](https://github.com/cri-o/cri-o)를 본다. +{{< /note >}} + ### 선행 조건 ```shell diff --git a/content/ko/docs/tasks/access-application-cluster/access-cluster.md b/content/ko/docs/tasks/access-application-cluster/access-cluster.md index 0be5cfc5ce..75929ae973 100644 --- a/content/ko/docs/tasks/access-application-cluster/access-cluster.md +++ b/content/ko/docs/tasks/access-application-cluster/access-cluster.md @@ -352,7 +352,7 @@ redirect 기능은 deprecated되고 제거 되었다. 대신 (아래의) proxy - 노드, 파드, 서비스에 접근하는 데 사용될 수 있다 - 서비스에 접근하는 데 사용되면 load balacing한다 -1. [kube proxy](/docs/concepts/services-networking/service/#ips-and-vips): +1. [kube proxy](/ko/docs/concepts/services-networking/service/#ips-and-vips): - 각 노드 상에서 실행된다 - UDP와 TCP를 proxy한다 diff --git a/content/ko/docs/tasks/access-application-cluster/web-ui-dashboard.md b/content/ko/docs/tasks/access-application-cluster/web-ui-dashboard.md index 46ca07d452..f9d87d9095 100644 --- a/content/ko/docs/tasks/access-application-cluster/web-ui-dashboard.md +++ b/content/ko/docs/tasks/access-application-cluster/web-ui-dashboard.md @@ -79,7 +79,7 @@ Kubeconfig 인증 방법은 외부 아이덴티티 프로파이더 또는 x509 클러스터에 의도한 파드의 수를 유지하기 위해서 [디플로이먼트](/ko/docs/concepts/workloads/controllers/deployment/)가 생성될 것이다. -- **서비스(Service)** (선택): 일부 애플리케이션의 경우, (예를 들어, 프론트엔드) 아마도 클러스터 바깥의 퍼블릭 IP 주소를 가진 (외부 서비스) 외부에 [서비스(Service)](/docs/concepts/services-networking/service/)를 노출 시키고 싶을 수 있다. 외부 서비스들을 위해, 한개 또는 여러 개의 포트들을 열어 둘 필요가 있다. [이 곳](/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/) 내용을 참고한다. +- **서비스(Service)** (선택): 일부 애플리케이션의 경우, (예를 들어, 프론트엔드) 아마도 클러스터 바깥의 퍼블릭 IP 주소를 가진 (외부 서비스) 외부에 [서비스(Service)](/ko/docs/concepts/services-networking/service/)를 노출 시키고 싶을 수 있다. 외부 서비스들을 위해, 한개 또는 여러 개의 포트들을 열어 둘 필요가 있다. [이 곳](/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/) 내용을 참고한다. 클러스터 내부에서만 보고 싶은 어떤 서비스(Serivce)들이 있을 것인다. 이를 내부 서비스라고 한다. diff --git a/content/ko/docs/tasks/debug-application-cluster/resource-usage-monitoring.md b/content/ko/docs/tasks/debug-application-cluster/resource-usage-monitoring.md index 9f1be04977..f563fae04b 100644 --- a/content/ko/docs/tasks/debug-application-cluster/resource-usage-monitoring.md +++ b/content/ko/docs/tasks/debug-application-cluster/resource-usage-monitoring.md @@ -8,7 +8,7 @@ title: 리소스 모니터링 도구 애플리케이션을 스케일하여 신뢰할 수 있는 서비스를 제공하려면, 애플리케이션이 배포되었을 때 애플리케이션이 어떻게 동작하는지를 이해해야 한다. 컨테이너, [파드](/ko/docs/concepts/workloads/pods/pod), -[서비스](/docs/concepts/services-networking/service), 그리고 전체 클러스터의 특성을 +[서비스](/ko/docs/concepts/services-networking/service), 그리고 전체 클러스터의 특성을 검사하여 쿠버네티스 클러스터 내의 애플리케이션 성능을 검사할 수 있다. 쿠버네티스는 각 레벨에서 애플리케이션의 리소스 사용량에 대한 상세 정보를 제공한다. 이 정보는 애플리케이션의 성능을 평가하고 diff --git a/content/ko/docs/tasks/manage-kubernetes-objects/declarative-config.md b/content/ko/docs/tasks/manage-kubernetes-objects/declarative-config.md index d47b6e7f31..dde6650e20 100644 --- a/content/ko/docs/tasks/manage-kubernetes-objects/declarative-config.md +++ b/content/ko/docs/tasks/manage-kubernetes-objects/declarative-config.md @@ -81,7 +81,14 @@ kubectl apply -f <디렉터리>/ kubectl diff -f https://k8s.io/examples/application/simple_deployment.yaml ``` {{< note >}} -`diff`는 `kube-apiserver`의 활성화가 필요한 [서버사이드 dry-run](/docs/reference/using-api/api-concepts/#dry-run)을 사용한다. +`diff`는 `kube-apiserver`의 활성화가 필요한 +[서버사이드 dry-run](/docs/reference/using-api/api-concepts/#dry-run)을 사용한다. + +`diff` 는 dry-run 모드에서 서버 측 적용 요청을 수행하므로, +`PATCH`, `CREATE`, 그리고 `UPDATE` 권한을 부여해야 한다. +자세한 것은 +[Dry-Run 인증](/docs/reference/using-api/api-concepts#dry-run-authorization)을 본다. + {{< /note >}} `kubectl apply`를 사용하여 오브젝트를 생성한다. diff --git a/content/ko/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough.md b/content/ko/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough.md index 418ebb17dc..5672b7809b 100644 --- a/content/ko/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough.md +++ b/content/ko/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough.md @@ -57,14 +57,19 @@ index.php는 CPU 과부하 연산을 수행한다. ?> ``` -첫 번째 단계로, 실행 중인 이미지의 디플로이먼트를 시작하고 서비스로 노출시킨다. +첫 번째 단계로, 다음 구성을 사용해서 실행 중인 이미지의 디플로이먼트를 +시작하고 서비스로 노출시킨다. +{{< codenew file="application/php-apache.yaml" >}} + + +다음의 명령어를 실행한다. ```shell -kubectl run php-apache --image=k8s.gcr.io/hpa-example --requests=cpu=200m --limits=cpu=500m --expose --port=80 +kubectl apply -f https://k8s.io/examples/application/php-apache.yaml ``` ``` -service/php-apache created deployment.apps/php-apache created +service/php-apache created ``` ## Horizontal Pod Autoscaler 생성 diff --git a/content/ko/docs/tasks/run-application/horizontal-pod-autoscale.md b/content/ko/docs/tasks/run-application/horizontal-pod-autoscale.md index 3f40a1b22b..4043ef3a13 100644 --- a/content/ko/docs/tasks/run-application/horizontal-pod-autoscale.md +++ b/content/ko/docs/tasks/run-application/horizontal-pod-autoscale.md @@ -158,15 +158,11 @@ HorizontalPodAutoscaler에 여러 메트릭이 지정된 경우, 이 계산은 현재 값보다 높은 `desiredReplicas` 을 제공하는 경우 HPA가 여전히 확장할 수 있음을 의미한다. -마지막으로, HPA가 목표를 스케일하기 직전에 스케일 권장 사항이 -기록된다. 컨트롤러는 구성 가능한 창(window) 내에서 가장 높은 권장 -사항을 선택하도록 해당 창 내의 모든 권장 사항을 고려한다. 이 값은 -`--horizontal-pod-autoscaler-downscale-stabilization` 플래그 또는 HPA 오브젝트 -동작 `behavior.scaleDown.stabilizationWindowSeconds` ([구성가능한 -스케일링 동작 지원](#구성가능한-스케일링-동작-지원)을 본다)을 -사용하여 설정할 수 있고, 기본 값은 5분이다. -즉, 스케일 다운이 점진적으로 발생하여 급격히 변동하는 메트릭 값의 -영향을 완만하게 한다. +마지막으로, HPA가 목표를 스케일하기 직전에 스케일 권장 사항이 기록된다. +컨트롤러는 구성 가능한 창(window) 내에서 가장 높은 권장 사항을 선택하도록 해당 창 내의 +모든 권장 사항을 고려한다. 이 값은 `--horizontal-pod-autoscaler-downscale-stabilization` 플래그를 사용하여 설정할 수 있고, 기본 값은 5분이다. +즉, 스케일 다운이 점진적으로 발생하여 급격히 변동하는 +메트릭 값의 영향을 완만하게 한다. ## API 오브젝트 @@ -213,6 +209,9 @@ Horizontal Pod Autoscaler를 사용하여 레플리카 그룹의 스케일을 평가된 메트릭의 동적인 특징 때문에 레플리카 수가 자주 변동할 수 있다. 이것은 때로는 *스래싱 (thrashing)* 이라고도 한다. +v1.6 부터 클러스터 운영자는 `kube-controller-manager` 컴포넌트의 플래그로 +노출된 글로벌 HPA 설정을 튜닝하여 이 문제를 완화할 수 있다. + v1.12부터는 새로운 알고리즘 업데이트가 업스케일 지연에 대한 필요성을 제거하였다. @@ -229,11 +228,6 @@ v1.12부터는 새로운 알고리즘 업데이트가 업스케일 지연에 대 있다. {{< /note >}} -v1.17 부터 v2beta2 API 필드에서 `behavior.scaleDown.stabilizationWindowSeconds` -를 설정하여 다운스케일 안정화 창을 HPA별로 설정할 수 있다. -[구성가능한 스케일링 -동작 지원](#구성가능한-스케일링-동작-지원)을 본다. - ## 멀티 메트릭을 위한 지원 Kubernetes 1.6은 멀티 메트릭을 기반으로 스케일링을 지원한다. `autoscaling/v2beta2` API @@ -284,154 +278,6 @@ API에 접속하려면 클러스터 관리자는 다음을 확인해야 한다. 어떻게 사용하는지에 대한 예시는 [커스텀 메트릭 사용하는 작업 과정](/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#autoscaling-on-multiple-metrics-and-custom-metrics)과 [외부 메트릭스 사용하는 작업 과정](/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#autoscaling-on-metrics-not-related-to-kubernetes-objects)을 참조한다. -## 구성가능한 스케일링 동작 지원 - -[v1.17](https://github.com/kubernetes/enhancements/blob/master/keps/sig-autoscaling/20190307-configurable-scale-velocity-for-hpa.md) -부터 `v2beta2` API는 HPA `behavior` 필드를 통해 -스케일링 동작을 구성할 수 있다. -동작은 `behavior` 필드 아래의 `scaleUp` 또는 `scaleDown` -섹션에서 스케일링 업과 다운을 위해 별도로 지정된다. 안정화 윈도우는 -스케일링 대상에서 레플리카 수의 플래핑(flapping)을 방지하는 -양방향에 대해 지정할 수 있다. 마찬가지로 스케일링 정책을 지정하면 -스케일링 중 레플리카 변경 속도를 제어할 수 있다. - -### 스케일링 정책 - -스펙의 `behavior` 섹션에 하나 이상의 스케일링 폴리시를 지정할 수 있다. -폴리시가 여러 개 지정된 경우 가장 많은 양의 변경을 -허용하는 정책이 기본적으로 선택된 폴리시이다. 다음 예시는 스케일 다운 중 이 -동작을 보여준다. - -```yaml -behavior: - scaleDown: - policies: - - type: Pods - value: 4 - periodSeconds: 60 - - type: Percent - value: 10 - periodSeconds: 60 -``` - -파드 수가 40개를 초과하면 두 번째 폴리시가 스케일링 다운에 사용된다. -예를 들어 80개의 레플리카가 있고 대상을 10개의 레플리카로 축소해야 하는 -경우 첫 번째 단계에서 8개의 레플리카가 스케일 다운 된다. 레플리카의 수가 72개일 때 -다음 반복에서 파드의 10%는 7.2 이지만, 숫자는 8로 올림된다. 오토스케일러 컨트롤러의 -각 루프에서 변경될 파드의 수는 현재 레플리카의 수에 따라 재계산된다. 레플리카의 수가 40 -미만으로 떨어지면 첫 번째 폴리시 _(파드들)_ 가 적용되고 한번에 -4개의 레플리카가 줄어든다. - -`periodSeconds` 는 폴리시가 참(true)으로 유지되어야 하는 기간을 나타낸다. -첫 번째 정책은 1분 내에 최대 4개의 레플리카를 스케일 다운할 수 있도록 허용한다. -두 번째 정책은 현재 레플리카의 최대 10%를 1분 내에 스케일 다운할 수 있도록 허용한다. - -확장 방향에 대해 `selectPolicy` 필드를 확인하여 폴리시 선택을 변경할 수 있다. -레플리카의 수를 최소로 변경할 수 있는 폴리시를 선택하는 `최소(Min)`로 값을 설정한다. -값을 `Disabled` 로 설정하면 해당 방향으로 스케일링이 완전히 -비활성화 된다. - -### 안정화 윈도우 - -안정화 윈도우는 스케일링에 사용되는 메트릭이 계속 변동할 때 레플리카의 플래핑을 -다시 제한하기 위해 사용된다. 안정화 윈도우는 스케일링을 방지하기 위해 과거부터 -계산된 의도한 상태를 고려하는 오토스케일링 알고리즘에 의해 사용된다. -다음의 예시에서 `scaleDown` 에 대해 안정화 윈도우가 지정되어있다. - -```yaml -scaleDown: - stabilizationWindowSeconds: 300 -``` - -메트릭이 대상을 축소해야하는 것을 나타내는 경우 알고리즘은 -이전에 계산된 의도한 상태를 살펴보고 지정된 간격의 최고 값을 사용한다. -위의 예시에서 지난 5분 동안 모든 의도한 상태가 고려된다. - -### 기본 동작 - -사용자 지정 스케일링을 사용하려면 일부 필드를 지정해야 한다. 사용자 정의해야 -하는 값만 지정할 수 있다. 이러한 사용자 지정 값은 기본값과 병합된다. 기본값은 HPA -알고리즘의 기존 동작과 일치한다. - -```yaml -behavior: - scaleDown: - stabilizationWindowSeconds: 300 - policies: - - type: Percent - value: 100 - periodSeconds: 15 - scaleUp: - stabilizationWindowSeconds: 0 - policies: - - type: Percent - value: 100 - periodSeconds: 15 - - type: Pods - value: 4 - periodSeconds: 15 - selectPolicy: Max -``` -안정화 윈도우의 스케일링 다운의 경우 _300_ 초(또는 제공된 -경우`--horizontal-pod-autoscaler-downscale-stabilization` 플래그의 값)이다. 스케일링 다운에서는 현재 -실행 중인 레플리카의 100%를 제거할 수 있는 단일 정책만 있으며, 이는 스케일링 -대상을 최소 허용 레플리카로 축소할 수 있음을 의미한다. -스케일링 업에는 안정화 윈도우가 없다. 메트릭이 대상을 스케일 업해야 한다고 표시된다면 대상이 즉시 스케일 업된다. -두 가지 폴리시가 있다. HPA가 정상 상태에 도달 할 때까지 15초 마다 -4개의 파드 또는 현재 실행 중인 레플리카의 100% 가 추가된다. - -### 예시: 다운스케일 안정화 윈도우 변경 - -사용자 지정 다운스케일 안정화 윈도우를 1분 동안 제공하기 위해 -다음 동작이 HPA에 추가된다. - -```yaml -behavior: - scaleDown: - stabilizationWindowSeconds: 60 -``` - -### 예시: 스케일 다운 비율 제한 - -HPA에 의해 파드가 제거되는 속도를 분당 10%로 제한하기 위해 -다음 동작이 HPA에 추가된다. - -```yaml -behavior: - scaleDown: - policies: - - type: Percent - value: 10 - periodSeconds: 60 -``` - -마지막으로 5개의 파드를 드롭하기 위해 다른 폴리시를 추가하고, 최소 선택 -전략을 추가할 수 있다. - -```yaml -behavior: - scaleDown: - policies: - - type: Percent - value: 10 - periodSeconds: 60 - - type: Pods - value: 5 - periodSeconds: 60 - selectPolicy: Max -``` - -### 예시: 스케일 다운 비활성화 - -`selectPolicy` 의 `Disabled` 값은 주어진 방향으로의 스케일링을 끈다. -따라서 다운 스케일링을 방지하기 위해 다음 폴리시가 사용된다. - -```yaml -behavior: - scaleDown: - selectPolicy: Disabled -``` - {{% /capture %}} {{% capture whatsnext %}} diff --git a/content/ko/docs/tasks/tools/install-minikube.md b/content/ko/docs/tasks/tools/install-minikube.md index e8de40ce96..b50856ff08 100644 --- a/content/ko/docs/tasks/tools/install-minikube.md +++ b/content/ko/docs/tasks/tools/install-minikube.md @@ -74,9 +74,17 @@ kubectl이 설치되었는지 확인한다. kubectl은 [kubectl 설치하고 설 • [VirtualBox](https://www.virtualbox.org/wiki/Downloads) -{{< note >}} -Minikube는 쿠버네티스 컴포넌트를 VM이 아닌 호스트에서도 동작하도록 `--vm-driver=none` 옵션도 지원한다. 이 드라이버를 사용하려면 [도커](https://www.docker.com/products/docker-desktop) 와 Linux 환경이 필요하지만, 하이퍼바이저는 필요하지 않는다. none 드라이버를 사용하려면 [도커](https://www.docker.com/products/docker-desktop) 에서 도커를 apt로 설치하기를 사용하는 것을 권장한다. 도커의 스냅 설치는 minikube에서 작동하지 않는다. -{{< /note >}} +Minikube는 쿠버네티스 컴포넌트를 VM이 아닌 호스트에서도 동작하도록 `--vm-driver=none` 옵션도 지원한다. +이 드라이버를 사용하려면 [도커](https://www.docker.com/products/docker-desktop) 와 Linux 환경이 필요하지만, 하이퍼바이저는 필요하지 않다. + +데비안(Debian) 또는 파생된 배포판에서 `none` 드라이버를 사용하는 경우, +Minikube에서는 동작하지 않는 스냅 패키지 대신 도커용 `.deb` 패키지를 사용한다. +[도커](https://www.docker.com/products/docker-desktop)에서 `.deb` 패키지를 다운로드 할 수 있다. + +{{< caution >}} +`none` VM 드라이버는 보안과 데이터 손실 이슈를 일으킬 수 있다. +`--vm-driver=none` 을 사용하기 전에 [이 문서](https://minikube.sigs.k8s.io/docs/reference/drivers/none/)를 참조해서 더 자세한 내용을 본다. +{{< /caution >}} ### 패키지를 이용하여 Minikube 설치 diff --git a/content/ko/docs/tutorials/clusters/apparmor.md b/content/ko/docs/tutorials/clusters/apparmor.md index 858bb59f58..e3f9246a4f 100644 --- a/content/ko/docs/tutorials/clusters/apparmor.md +++ b/content/ko/docs/tutorials/clusters/apparmor.md @@ -329,7 +329,7 @@ Events: 현재 쿠버네티스는 AppArmor 프로파일을 노드에 적재하기 위한 네이티브 메커니즘을 제공하지 않는다. 프로파일을 설정하는 여러 방법이 있다. 예를 들면 다음과 같다. -* 각 노드에서 파드를 실행하는 [데몬셋](/docs/concepts/workloads/controllers/daemonset/)을 통해서 +* 각 노드에서 파드를 실행하는 [데몬셋](/ko/docs/concepts/workloads/controllers/daemonset/)을 통해서 올바른 프로파일이 적재되었는지 확인한다. 예시 구현은 [여기](https://git.k8s.io/kubernetes/test/images/apparmor-loader)에서 찾아볼 수 있다. * 노드 초기화 시간에 노드 초기화 스크립트(예를 들어 Salt, Ansible 등)나 @@ -340,7 +340,7 @@ Events: 스케줄러는 어떤 프로파일이 어떤 노드에 적재되는지 고려하지 않으니, 프로파일 전체 집합이 모든 노드에 적재되어야 한다. 대안적인 방법은 각 프로파일(혹은 프로파일의 클래스)을 위한 노드 레이블을 노드에 추가하고, -[노드 셀렉터](/docs/concepts/configuration/assign-pod-node/)를 이용하여 +[노드 셀렉터](/ko/docs/concepts/configuration/assign-pod-node/)를 이용하여 파드가 필요한 프로파일이 있는 노드에서 실행되도록 한다. ### PodSecurityPolicy로 프로파일 제한하기 {#restricting-profiles-with-the-podsecuritypolicy} diff --git a/content/ko/docs/tutorials/hello-minikube.md b/content/ko/docs/tutorials/hello-minikube.md index e24b887509..b4209de162 100644 --- a/content/ko/docs/tutorials/hello-minikube.md +++ b/content/ko/docs/tutorials/hello-minikube.md @@ -117,7 +117,7 @@ Katacode는 무료로 브라우저에서 쿠버네티스 환경을 제공한다. ```shell kubectl config view ``` - + {{< note >}}`kubectl` 명령어에 관해 자세히 알기 원하면 [kubectl 개관](/docs/user-guide/kubectl-overview/)을 살펴보자.{{< /note >}} ## 서비스 만들기 @@ -125,14 +125,14 @@ Katacode는 무료로 브라우저에서 쿠버네티스 환경을 제공한다. 기본적으로 파드는 쿠버네티스 클러스터 내부의 IP 주소로만 접근할 수 있다. `hello-node` 컨테이너를 쿠버네티스 가상 네트워크 외부에서 접근하려면 파드를 쿠버네티스 -[*서비스*](/docs/concepts/services-networking/service/)로 노출해야 한다. +[*서비스*](/ko/docs/concepts/services-networking/service/)로 노출해야 한다. 1. `kubectl expose` 명령어로 퍼블릭 인터넷에 파드 노출하기 ```shell kubectl expose deployment hello-node --type=LoadBalancer --port=8080 ``` - + `--type=LoadBalancer`플래그는 클러스터 밖의 서비스로 노출하기 원한다는 뜻이다. @@ -198,13 +198,13 @@ Minikube에는 활성화하거나 비활성화 할 수 있고 로컬 쿠버네 storage-provisioner: enabled storage-provisioner-gluster: disabled ``` - + 2. 한 애드온을 활성화 한다. 예를 들어 `metrics-server` ```shell minikube addons enable metrics-server ``` - + 다음과 유사하게 출력된다. ``` @@ -245,7 +245,7 @@ Minikube에는 활성화하거나 비활성화 할 수 있고 로컬 쿠버네 ```shell minikube addons disable metrics-server ``` - + 다음과 유사하게 출력된다. ``` @@ -278,7 +278,7 @@ minikube delete {{% capture whatsnext %}} * [디플로이먼트 오브젝트](/ko/docs/concepts/workloads/controllers/deployment/)에 대해서 더 배워 본다. -* [애플리케이션 배포](/docs/user-guide/deploying-applications/)에 대해서 더 배워 본다. -* [서비스 오브젝트](/docs/concepts/services-networking/service/)에 대해서 더 배워 본다. +* [애플리케이션 배포](/docs/tasks/run-application/run-stateless-application-deployment/)에 대해서 더 배워 본다. +* [서비스 오브젝트](/ko/docs/concepts/services-networking/service/)에 대해서 더 배워 본다. {{% /capture %}} diff --git a/content/ko/docs/tutorials/services/source-ip.md b/content/ko/docs/tutorials/services/source-ip.md index 719ab6e1b7..23ba647830 100644 --- a/content/ko/docs/tutorials/services/source-ip.md +++ b/content/ko/docs/tutorials/services/source-ip.md @@ -23,8 +23,8 @@ content_template: templates/tutorial * [NAT](https://en.wikipedia.org/wiki/Network_address_translation): 네트워크 주소 변환 * [소스 NAT](https://en.wikipedia.org/wiki/Network_address_translation#SNAT): 패킷 상의 소스 IP 주소를 변경함, 보통 노드의 IP 주소 * [대상 NAT](https://en.wikipedia.org/wiki/Network_address_translation#DNAT): 패킷 상의 대상 IP 주소를 변경함, 보통 파드의 IP 주소 -* [VIP](/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies): 가상 IP 주소, 모든 쿠버네티스 서비스에 할당된 것 같은 -* [Kube-proxy](/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies): 네트워크 데몬으로 모든 노드에서 서비스 VIP 관리를 관리한다. +* [VIP](/ko/docs/concepts/services-networking/service/#가상-ip와-서비스-프록시): 가상 IP 주소, 모든 쿠버네티스 서비스에 할당된 것 같은 +* [Kube-proxy](/ko/docs/concepts/services-networking/service/#가상-ip와-서비스-프록시): 네트워크 데몬으로 모든 노드에서 서비스 VIP 관리를 관리한다. ## 전제 조건 @@ -34,7 +34,7 @@ content_template: templates/tutorial 작은 nginx 웹 서버를 이용한다. 다음과 같이 생성할 수 있다. ```console -kubectl run source-ip-app --image=k8s.gcr.io/echoserver:1.4 +kubectl create deployment source-ip-app --image=k8s.gcr.io/echoserver:1.4 ``` 출력은 다음과 같다. ``` @@ -57,7 +57,7 @@ deployment.apps/source-ip-app created ## Type=ClusterIP인 서비스에서 소스 IP 쿠버네티스 1.2부터 기본으로 제공하는 -[iptables 모드](/docs/concepts/services-networking/service/#proxy-mode-iptables)로 운영하는 경우 +[iptables 모드](/ko/docs/concepts/services-networking/service/#proxy-mode-iptables)로 운영하는 경우 클러스터 내에서 클러스터 IP로 패킷을 보내면 소스 NAT를 통과하지 않는다. Kube-proxy는 이 모드를 `proxyMode` 엔드포인트를 통해 노출한다. @@ -122,7 +122,7 @@ client_address는 클라이언트 파드와 서버 파드가 같은 노드 또 ## Type=NodePort인 서비스에서 소스 IP -쿠버네티스 1.5부터 [Type=NodePort](/docs/concepts/services-networking/service/#nodeport)인 서비스로 보내진 패킷은 +쿠버네티스 1.5부터 [Type=NodePort](/ko/docs/concepts/services-networking/service/#nodeport)인 서비스로 보내진 패킷은 소스 NAT가 기본으로 적용된다. `NodePort` 서비스를 생성하여 이것을 테스트할 수 있다. ```console @@ -221,7 +221,7 @@ client_address=104.132.1.79 ## Type=LoadBalancer인 서비스에서 소스 IP -쿠버네티스 1.5 부터 [Type=LoadBalancer](/docs/concepts/services-networking/service/#loadbalancer)인 서비스로 +쿠버네티스 1.5 부터 [Type=LoadBalancer](/ko/docs/concepts/services-networking/service/#loadbalancer)인 서비스로 보낸 패킷은 소스 NAT를 기본으로 하는데, `Ready` 상태로 모든 스케줄된 모든 쿠버네티스 노드는 로드 밸런싱 트래픽에 적합하다. 따라서 엔드포인트가 없는 노드에 패킷이 도착하면 시스템은 엔드포인트를 *포함한* 노드에 프록시를 diff --git a/content/ko/docs/tutorials/stateful-application/basic-stateful-set.md b/content/ko/docs/tutorials/stateful-application/basic-stateful-set.md index 45056e8622..59fdbbc7e3 100644 --- a/content/ko/docs/tutorials/stateful-application/basic-stateful-set.md +++ b/content/ko/docs/tutorials/stateful-application/basic-stateful-set.md @@ -17,7 +17,7 @@ weight: 10 * [파드](/docs/user-guide/pods/single-container/) * [클러스터 DNS(Cluster DNS)](/ko/docs/concepts/services-networking/dns-pod-service/) -* [헤드리스 서비스(Headless Services)](/docs/concepts/services-networking/service/#headless-services) +* [헤드리스 서비스(Headless Services)](/ko/docs/concepts/services-networking/service/#헤드리스-headless-서비스) * [퍼시스턴트볼륨(PersistentVolumes)](/docs/concepts/storage/persistent-volumes/) * [퍼시턴트볼륨 프로비저닝](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/persistent-volume-provisioning/) * [스테이트풀셋](/ko/docs/concepts/workloads/controllers/statefulset/) @@ -51,7 +51,7 @@ weight: 10 아래 예제를 이용해서 스테이트풀셋을 생성하자. 이는 [스테이트풀셋](/ko/docs/concepts/workloads/controllers/statefulset/) 개념에서 보인 예제와 유사하다. 이것은 `web`과 이 스테이트풀셋 파드의 IP 주소를 게시하는 -[헤드리스 서비스](/docs/concepts/services-networking/service/#headless-services)인 +[헤드리스 서비스](/ko/docs/concepts/services-networking/service/#헤드리스-headless-서비스)인 `nginx` 를 생성한다. {{< codenew file="application/web/web.yaml" >}} diff --git a/content/ko/docs/tutorials/stateful-application/cassandra.md b/content/ko/docs/tutorials/stateful-application/cassandra.md index 10c011aa3b..72c090988c 100644 --- a/content/ko/docs/tutorials/stateful-application/cassandra.md +++ b/content/ko/docs/tutorials/stateful-application/cassandra.md @@ -29,7 +29,7 @@ weight: 30 {{% /capture %}} {{% capture objectives %}} -* 카산드라 헤드리스 [*서비스*](/docs/concepts/services-networking/service/)를 생성하고 검증한다. +* 카산드라 헤드리스 [*서비스*](/ko/docs/concepts/services-networking/service/)를 생성하고 검증한다. * [스테이트풀셋](/ko/docs/concepts/workloads/controllers/statefulset/)을 이용하여 카산드라 링을 생성한다. * [스테이트풀셋](/ko/docs/concepts/workloads/controllers/statefulset/)을 검증한다. * [스테이트풀셋](/ko/docs/concepts/workloads/controllers/statefulset/)을 수정한다. @@ -37,7 +37,7 @@ weight: 30 {{% /capture %}} {{% capture prerequisites %}} -이 튜토리얼을 완료하려면, [파드](/ko/docs/concepts/workloads/pods/pod/), [서비스](/docs/concepts/services-networking/service/), [스테이트풀셋](/ko/docs/concepts/workloads/controllers/statefulset/)의 기본 개념에 친숙해야한다. 추가로 +이 튜토리얼을 완료하려면, [파드](/ko/docs/concepts/workloads/pods/pod/), [서비스](/ko/docs/concepts/services-networking/service/), [스테이트풀셋](/ko/docs/concepts/workloads/controllers/statefulset/)의 기본 개념에 친숙해야한다. 추가로 * *kubectl* 커맨드라인 도구를 [설치와 설정](/docs/tasks/tools/install-kubectl/)하자. @@ -65,7 +65,7 @@ minikube start --memory 5120 --cpus=4 {{% capture lessoncontent %}} ## 카산드라 헤드리스 서비스 생성하기 -쿠버네티스 [서비스](/docs/concepts/services-networking/service/)는 동일 작업을 수행하는 [파드](/ko/docs/concepts/workloads/pods/pod/)의 집합을 기술한다. +쿠버네티스 [서비스](/ko/docs/concepts/services-networking/service/)는 동일 작업을 수행하는 [파드](/ko/docs/concepts/workloads/pods/pod/)의 집합을 기술한다. 다음의 `서비스`는 쿠버네티스 클러스터에서 카산드라 파드와 클라이언트 간에 DNS 찾아보기 용도로 사용한다. diff --git a/content/ko/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume.md b/content/ko/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume.md index 1f419fdaf3..603a857a58 100644 --- a/content/ko/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume.md +++ b/content/ko/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume.md @@ -233,7 +233,7 @@ kubectl apply -k ./ * [인트로스펙션과 디버깅](/docs/tasks/debug-application-cluster/debug-application-introspection/)를 알아보자. * [잡](/docs/concepts/workloads/controllers/jobs-run-to-completion/)를 알아보자. -* [포트 포워딩](/docs/tasks/access-application-cluster/port-forward-access-application-cluster/)를 알아보자. +* [포트 포워딩](/ko/docs/tasks/access-application-cluster/port-forward-access-application-cluster/)를 알아보자. * 어떻게 [컨테이너에서 셸을 사용하는지](/docs/tasks/debug-application-cluster/get-shell-running-container/)를 알아보자. {{% /capture %}} diff --git a/content/ko/docs/tutorials/stateful-application/zookeeper.md b/content/ko/docs/tutorials/stateful-application/zookeeper.md index 06dc81fed4..7486a7fe71 100644 --- a/content/ko/docs/tutorials/stateful-application/zookeeper.md +++ b/content/ko/docs/tutorials/stateful-application/zookeeper.md @@ -6,9 +6,9 @@ weight: 40 {{% capture overview %}} 이 튜토리얼은 [아파치 ZooKeeper](https://zookeeper.apache.org) -쿠버네티스에서 [스테이트풀셋](/docs/concepts/workloads/controllers/statefulset/)과 -[파드디스룹선버짓(PodDisruptionBudget)](/docs/concepts/workloads/pods/disruptions/#specifying-a-poddisruptionbudget)과 -[파드안티어피니티(PodAntiAffinity)](/docs/user-guide/node-selection/#inter-pod-affinity-and-anti-affinity-beta-feature)를 이용한 [Apache Zookeeper](https://zookeeper.apache.org) 실행을 설명한다. +쿠버네티스에서 [스테이트풀셋](/ko/docs/concepts/workloads/controllers/statefulset/)과 +[파드디스룹선버짓(PodDisruptionBudget)](/ko/docs/concepts/workloads/pods/disruptions/#specifying-a-poddisruptionbudget)과 +[파드안티어피니티(PodAntiAffinity)](/ko/docs/user-guide/node-selection/#파드간-어피니티와-안티-어피니티)를 이용한 [Apache Zookeeper](https://zookeeper.apache.org) 실행을 설명한다. {{% /capture %}} {{% capture prerequisites %}} @@ -18,12 +18,12 @@ weight: 40 - [파드](/docs/user-guide/pods/single-container/) - [클러스터 DNS](/ko/docs/concepts/services-networking/dns-pod-service/) -- [헤드리스 서비스](/docs/concepts/services-networking/service/#headless-services) +- [헤드리스 서비스](/ko/docs/concepts/services-networking/service/#헤드리스-headless-서비스) - [퍼시스턴트볼륨](/docs/concepts/storage/volumes/) - [퍼시스턴트볼륨 프로비저닝](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/persistent-volume-provisioning/) - [스테이트풀셋](/ko/docs/concepts/workloads/controllers/statefulset/) - [파드디스룹션버짓](/ko/docs/concepts/workloads/pods/disruptions/#specifying-a-poddisruptionbudget) -- [파드안티어피니티](/docs/user-guide/node-selection/#inter-pod-affinity-and-anti-affinity-beta-feature) +- [파드안티어피니티](/ko/docs/user-guide/node-selection/#파드간-어피니티와-안티-어피니티) - [kubectl CLI](/docs/user-guide/kubectl/) 최소한 4개의 노드가 있는 클러스터가 필요하며, 각 노드는 적어도 2 개의 CPU와 4 GiB 메모리가 필요하다. 이 튜토리얼에서 클러스터 노드를 통제(cordon)하고 비우게(drain) 할 것이다. **이것은 클러스터를 종료하여 노드의 모든 파드를 퇴출(evict)하는 것으로, 모든 파드는 임시로 언스케줄된다는 의미이다.** 이 튜토리얼을 위해 전용 클러스터를 이용하거나, 다른 테넌트에 간섭을 하는 혼란이 발생하지 않도록 해야 합니다. @@ -62,8 +62,8 @@ ZooKeeper는 전체 상태 머신을 메모리에 보존하고 모든 돌연변 ## ZooKeeper 앙상블 생성하기 아래 메니페스트에는 -[헤드리스 서비스](/docs/concepts/services-networking/service/#headless-services), -[서비스](/docs/concepts/services-networking/service/), +[헤드리스 서비스](/ko/docs/concepts/services-networking/service/#헤드리스-headless-서비스), +[서비스](/ko/docs/concepts/services-networking/service/), [파드디스룹션버짓](/ko/docs/concepts/workloads/pods/disruptions//#specifying-a-poddisruptionbudget), [스테이트풀셋](/ko/docs/concepts/workloads/controllers/statefulset/)을 포함한다. diff --git a/content/ko/docs/tutorials/stateless-application/expose-external-ip-address.md b/content/ko/docs/tutorials/stateless-application/expose-external-ip-address.md index 78b72c9e73..0f7360273e 100644 --- a/content/ko/docs/tutorials/stateless-application/expose-external-ip-address.md +++ b/content/ko/docs/tutorials/stateless-application/expose-external-ip-address.md @@ -80,8 +80,17 @@ kubectl apply -f https://k8s.io/examples/service/load-balancer-example.yaml NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE my-service LoadBalancer 10.3.245.137 104.198.205.71 8080/TCP 54s - 참고: 만약 외부 IP 주소가 \으로 표시되면 잠시 기다린 다음, - 동일한 명령어를 다시 입력한다. + {{< note >}} + + `type=LoadBalancer` 서비스는 이 예시에서 다루지 않은 외부 클라우드 공급자가 지원하며, 자세한 내용은 [이 페이지](/ko/docs/concepts/services-networking/service/#loadbalancer를 참조한다. + + {{< /note >}} + + {{< note >}} + + 만약 외부 IP 주소가 \으로 표시되면 잠시 기다린 다음, 동일한 명령어를 다시 입력한다. + + {{< /note >}} 1. 서비스에 대한 자세한 정보를 확인한다. diff --git a/content/ko/docs/tutorials/stateless-application/guestbook.md b/content/ko/docs/tutorials/stateless-application/guestbook.md index a1f24755b8..4753c83b93 100644 --- a/content/ko/docs/tutorials/stateless-application/guestbook.md +++ b/content/ko/docs/tutorials/stateless-application/guestbook.md @@ -77,7 +77,7 @@ POD-NAME을 해당 파드 이름으로 수정해야 한다. ### Redis 마스터 서비스 생성하기 -방명록 애플리케이션에서 데이터를 쓰려면 Redis 마스터와 통신해야 한다. Redis 마스터 파드로 트래픽을 프록시하려면 [서비스](/docs/concepts/services-networking/service/)를 적용해야 한다. 서비스는 파드에 접근하기 위한 정책을 정의한다. +방명록 애플리케이션에서 데이터를 쓰려면 Redis 마스터와 통신해야 한다. Redis 마스터 파드로 트래픽을 프록시하려면 [서비스](/ko/docs/concepts/services-networking/service/)를 적용해야 한다. 서비스는 파드에 접근하기 위한 정책을 정의한다. {{< codenew file="application/guestbook/redis-master-service.yaml" >}} @@ -197,7 +197,7 @@ Redis 마스터는 단일 파드이지만, 복제된 Redis 슬레이브를 추 ### 프론트엔드 서비스 생성하기 -서비스의 기본 유형은 [ClusterIP](/docs/concepts/services-networking/service/#publishing-services---service-types)이기 때문에 적용한 redis-slave 및 redis-master 서비스는 컨테이너 클러스터 내에서만 접근할 수 있다. `ClusterIP`는 서비스가 가리키는 파드 집합에 대한 단일 IP 주소를 제공한다. 이 IP 주소는 클러스터 내에서만 접근할 수 있다. +서비스의 기본 유형은 [ClusterIP](/ko/docs/concepts/services-networking/service/#publishing-services-service-types)이기 때문에 적용한 redis-slave 및 redis-master 서비스는 컨테이너 클러스터 내에서만 접근할 수 있다. `ClusterIP`는 서비스가 가리키는 파드 집합에 대한 단일 IP 주소를 제공한다. 이 IP 주소는 클러스터 내에서만 접근할 수 있다. 게스트가 방명록에 접근할 수 있도록 하려면, 외부에서 볼 수 있도록 프론트엔드 서비스를 구성해야 한다. 그렇게 하면 클라이언트가 컨테이너 클러스터 외부에서 서비스를 요청할 수 있다. Minikube는 `NodePort`를 통해서만 서비스를 노출할 수 있다. diff --git a/content/ko/examples/application/php-apache.yaml b/content/ko/examples/application/php-apache.yaml new file mode 100644 index 0000000000..5eb04cfb89 --- /dev/null +++ b/content/ko/examples/application/php-apache.yaml @@ -0,0 +1,39 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: php-apache +spec: + selector: + matchLabels: + run: php-apache + replicas: 1 + template: + metadata: + labels: + run: php-apache + spec: + containers: + - name: php-apache + image: k8s.gcr.io/hpa-example + ports: + - containerPort: 80 + resources: + limits: + cpu: 500m + requests: + cpu: 200m + +--- + +apiVersion: v1 +kind: Service +metadata: + name: php-apache + labels: + run: php-apache +spec: + ports: + - port: 80 + selector: + run: php-apache + diff --git a/content/ko/examples/service/networking/network-policy-allow-all-egress.yaml b/content/ko/examples/service/networking/network-policy-allow-all-egress.yaml new file mode 100644 index 0000000000..42b2a2a296 --- /dev/null +++ b/content/ko/examples/service/networking/network-policy-allow-all-egress.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-all-egress +spec: + podSelector: {} + egress: + - {} + policyTypes: + - Egress diff --git a/content/ko/examples/service/networking/network-policy-allow-all-ingress.yaml b/content/ko/examples/service/networking/network-policy-allow-all-ingress.yaml new file mode 100644 index 0000000000..462912dae4 --- /dev/null +++ b/content/ko/examples/service/networking/network-policy-allow-all-ingress.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-all-ingress +spec: + podSelector: {} + ingress: + - {} + policyTypes: + - Ingress diff --git a/content/ko/examples/service/networking/network-policy-default-deny-all.yaml b/content/ko/examples/service/networking/network-policy-default-deny-all.yaml new file mode 100644 index 0000000000..5c0086bd71 --- /dev/null +++ b/content/ko/examples/service/networking/network-policy-default-deny-all.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: default-deny-all +spec: + podSelector: {} + policyTypes: + - Ingress + - Egress diff --git a/content/ko/examples/service/networking/network-policy-default-deny-egress.yaml b/content/ko/examples/service/networking/network-policy-default-deny-egress.yaml new file mode 100644 index 0000000000..a4659e1417 --- /dev/null +++ b/content/ko/examples/service/networking/network-policy-default-deny-egress.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: default-deny-egress +spec: + podSelector: {} + policyTypes: + - Egress diff --git a/content/ko/examples/service/networking/network-policy-default-deny-ingress.yaml b/content/ko/examples/service/networking/network-policy-default-deny-ingress.yaml new file mode 100644 index 0000000000..e823802487 --- /dev/null +++ b/content/ko/examples/service/networking/network-policy-default-deny-ingress.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: default-deny-ingress +spec: + podSelector: {} + policyTypes: + - Ingress From 55de25393429a94c92b98a883cbd30b0062c8eeb Mon Sep 17 00:00:00 2001 From: Yong Zhang Date: Fri, 28 Feb 2020 17:22:39 +0800 Subject: [PATCH 097/111] =?UTF-8?q?Localize=20=E2=80=9Cemail=20address?= =?UTF-8?q?=E2=80=9D=20placeholder=20on=20home=20page=20(#19359)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- i18n/en.toml | 3 +++ layouts/index.html | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/i18n/en.toml b/i18n/en.toml index b829bc87da..48c0c5f469 100644 --- a/i18n/en.toml +++ b/i18n/en.toml @@ -189,3 +189,6 @@ other = "Warning:" [whatsnext_heading] other = "What's next" + +[input_placeholder_email_address] +other = "email address" \ No newline at end of file diff --git a/layouts/index.html b/layouts/index.html index d3fd401d78..955bd6a934 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -25,7 +25,7 @@

{{ T "main_kubeweekly_baseline" }}


- +
From fc3a741b1e612a10ff25f3172045abfe4c5ce276 Mon Sep 17 00:00:00 2001 From: Cria Hu Date: Fri, 28 Feb 2020 18:40:38 +0800 Subject: [PATCH 098/111] Modify sentences with poor translation (#19366) --- content/zh/docs/tutorials/hello-minikube.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/zh/docs/tutorials/hello-minikube.md b/content/zh/docs/tutorials/hello-minikube.md index 7550f80dff..a8587d6967 100644 --- a/content/zh/docs/tutorials/hello-minikube.md +++ b/content/zh/docs/tutorials/hello-minikube.md @@ -171,7 +171,7 @@ Pod runs a Container based on the provided Docker image. --> ## 创建 Deployment -Kubernetes [*Pod*](/docs/concepts/workloads/pods/pod/) 是由一个或多个容器为了管理和联网的目的而绑定在一起构成的组。本教程中的 Pod 只有一个容器。Kubernetes [*Deployment*](/docs/concepts/workloads/controllers/deployment/) 检查 Pod 的健康状况,并在 Pod 中的容器终止的情况下重新启动新的容器。Deployment 是管理 Pod 创建和扩展的推荐方法。 +Kubernetes [*Pod*](/docs/concepts/workloads/pods/pod/) 是由一个或多个为了管理和联网而绑定在一起的容器构成的组。本教程中的 Pod 只有一个容器。Kubernetes [*Deployment*](/docs/concepts/workloads/controllers/deployment/) 检查 Pod 的健康状况,并在 Pod 中的容器终止的情况下重新启动新的容器。Deployment 是管理 Pod 创建和扩展的推荐方法。 1. 使用 `kubectl create` 命令创建管理 Pod 的 Deployment。该 Pod 根据提供的 Docker 镜像运行 Container。 From 6318dbb124b3956979c52fee6ae71a0876b7c43c Mon Sep 17 00:00:00 2001 From: Qiming Teng Date: Sat, 29 Feb 2020 04:10:38 +0800 Subject: [PATCH 099/111] Resource name constraints (2) (#19119) xref: #17969, #19099, #18746 --- .../api-extension/custom-resources.md | 7 ++++++- .../workloads/controllers/daemonset.md | 6 +++++- .../workloads/controllers/deployment.md | 2 ++ .../workloads/controllers/replicaset.md | 18 +++++++++++++++++- .../workloads/controllers/statefulset.md | 5 +++++ .../configure-aggregation-layer.md | 3 +++ .../tasks/manage-daemon/rollback-daemon-set.md | 3 ++- 7 files changed, 40 insertions(+), 4 deletions(-) diff --git a/content/en/docs/concepts/extend-kubernetes/api-extension/custom-resources.md b/content/en/docs/concepts/extend-kubernetes/api-extension/custom-resources.md index c96ae1f5c7..15f3f7e234 100644 --- a/content/en/docs/concepts/extend-kubernetes/api-extension/custom-resources.md +++ b/content/en/docs/concepts/extend-kubernetes/api-extension/custom-resources.md @@ -128,7 +128,12 @@ Regardless of how they are installed, the new resources are referred to as Custo ## CustomResourceDefinitions -The [CustomResourceDefinition](/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/) API resource allows you to define custom resources. Defining a CRD object creates a new custom resource with a name and schema that you specify. The Kubernetes API serves and handles the storage of your custom resource. +The [CustomResourceDefinition](/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/) +API resource allows you to define custom resources. +Defining a CRD object creates a new custom resource with a name and schema that you specify. +The Kubernetes API serves and handles the storage of your custom resource. +The name of a CRD object must be a valid +[DNS subdomain name](/docs/concepts/overview/working-with-objects/names#dns-subdomain-names). This frees you from writing your own API server to handle the custom resource, but the generic nature of the implementation means you have less flexibility than with diff --git a/content/en/docs/concepts/workloads/controllers/daemonset.md b/content/en/docs/concepts/workloads/controllers/daemonset.md index 8627978427..f2feb36515 100644 --- a/content/en/docs/concepts/workloads/controllers/daemonset.md +++ b/content/en/docs/concepts/workloads/controllers/daemonset.md @@ -39,7 +39,8 @@ You can describe a DaemonSet in a YAML file. For example, the `daemonset.yaml` f {{< codenew file="controllers/daemonset.yaml" >}} -* Create a DaemonSet based on the YAML file: +Create a DaemonSet based on the YAML file: + ``` kubectl apply -f https://k8s.io/examples/controllers/daemonset.yaml ``` @@ -50,6 +51,9 @@ As with all other Kubernetes config, a DaemonSet needs `apiVersion`, `kind`, and general information about working with config files, see [deploying applications](/docs/user-guide/deploying-applications/), [configuring containers](/docs/tasks/), and [object management using kubectl](/docs/concepts/overview/working-with-objects/object-management/) documents. +The name of a DaemonSet object must be a valid +[DNS subdomain name](/docs/concepts/overview/working-with-objects/names#dns-subdomain-names). + A DaemonSet also needs a [`.spec`](https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status) section. ### Pod Template diff --git a/content/en/docs/concepts/workloads/controllers/deployment.md b/content/en/docs/concepts/workloads/controllers/deployment.md index 6e83992421..03c58c6525 100644 --- a/content/en/docs/concepts/workloads/controllers/deployment.md +++ b/content/en/docs/concepts/workloads/controllers/deployment.md @@ -1020,6 +1020,8 @@ can create multiple Deployments, one for each release, following the canary patt As with all other Kubernetes configs, a Deployment needs `apiVersion`, `kind`, and `metadata` fields. For general information about working with config files, see [deploying applications](/docs/tutorials/stateless-application/run-stateless-application-deployment/), configuring containers, and [using kubectl to manage resources](/docs/concepts/overview/working-with-objects/object-management/) documents. +The name of a Deployment object must be a valid +[DNS subdomain name](/docs/concepts/overview/working-with-objects/names#dns-subdomain-names). A Deployment also needs a [`.spec` section](https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status). diff --git a/content/en/docs/concepts/workloads/controllers/replicaset.md b/content/en/docs/concepts/workloads/controllers/replicaset.md index 42451f0089..5e8c6d67f3 100644 --- a/content/en/docs/concepts/workloads/controllers/replicaset.md +++ b/content/en/docs/concepts/workloads/controllers/replicaset.md @@ -58,22 +58,26 @@ kubectl apply -f https://kubernetes.io/examples/controllers/frontend.yaml ``` You can then get the current ReplicaSets deployed: + ```shell kubectl get rs ``` And see the frontend one you created: + ```shell NAME DESIRED CURRENT READY AGE frontend 3 3 3 6s ``` -You can also check on the state of the replicaset: +You can also check on the state of the ReplicaSet: + ```shell kubectl describe rs/frontend ``` And you will see output similar to: + ```shell Name: frontend Namespace: default @@ -103,11 +107,13 @@ Events: ``` And lastly you can check for the Pods brought up: + ```shell kubectl get pods ``` You should see Pod information similar to: + ```shell NAME READY STATUS RESTARTS AGE frontend-b2zdv 1/1 Running 0 6m36s @@ -117,11 +123,13 @@ frontend-wtsmm 1/1 Running 0 6m36s You can also verify that the owner reference of these pods is set to the frontend ReplicaSet. To do this, get the yaml of one of the Pods running: + ```shell kubectl get pods frontend-b2zdv -o yaml ``` The output will look similar to this, with the frontend ReplicaSet's info set in the metadata's ownerReferences field: + ```shell apiVersion: v1 kind: Pod @@ -166,11 +174,13 @@ The new Pods will be acquired by the ReplicaSet, and then immediately terminated its desired count. Fetching the Pods: + ```shell kubectl get pods ``` The output shows that the new Pods are either already terminated, or in the process of being terminated: + ```shell NAME READY STATUS RESTARTS AGE frontend-b2zdv 1/1 Running 0 10m @@ -181,17 +191,20 @@ pod2 0/1 Terminating 0 1s ``` If you create the Pods first: + ```shell kubectl apply -f https://kubernetes.io/examples/pods/pod-rs.yaml ``` And then create the ReplicaSet however: + ```shell kubectl apply -f https://kubernetes.io/examples/controllers/frontend.yaml ``` You shall see that the ReplicaSet has acquired the Pods and has only created new ones according to its spec until the number of its new Pods and the original matches its desired count. As fetching the Pods: + ```shell kubectl get pods ``` @@ -213,6 +226,9 @@ For ReplicaSets, the kind is always just ReplicaSet. In Kubernetes 1.9 the API version `apps/v1` on the ReplicaSet kind is the current version and is enabled by default. The API version `apps/v1beta2` is deprecated. Refer to the first lines of the `frontend.yaml` example for guidance. +The name of a ReplicaSet object must be a valid +[DNS subdomain name](/docs/concepts/overview/working-with-objects/names#dns-subdomain-names). + A ReplicaSet also needs a [`.spec` section](https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status). ### Pod Template diff --git a/content/en/docs/concepts/workloads/controllers/statefulset.md b/content/en/docs/concepts/workloads/controllers/statefulset.md index 4519cb4bec..aa6a07788b 100644 --- a/content/en/docs/concepts/workloads/controllers/statefulset.md +++ b/content/en/docs/concepts/workloads/controllers/statefulset.md @@ -109,10 +109,15 @@ In the above example: * The StatefulSet, named `web`, has a Spec that indicates that 3 replicas of the nginx container will be launched in unique Pods. * The `volumeClaimTemplates` will provide stable storage using [PersistentVolumes](/docs/concepts/storage/persistent-volumes/) provisioned by a PersistentVolume Provisioner. +The name of a StatefulSet object must be a valid +[DNS subdomain name](/docs/concepts/overview/working-with-objects/names#dns-subdomain-names). + ## Pod Selector + You must set the `.spec.selector` field of a StatefulSet to match the labels of its `.spec.template.metadata.labels`. Prior to Kubernetes 1.8, the `.spec.selector` field was defaulted when omitted. In 1.8 and later versions, failing to specify a matching Pod Selector will result in a validation error during StatefulSet creation. ## Pod Identity + StatefulSet Pods have a unique identity that is comprised of an ordinal, a stable network identity, and stable storage. The identity sticks to the Pod, regardless of which node it's (re)scheduled on. diff --git a/content/en/docs/tasks/access-kubernetes-api/configure-aggregation-layer.md b/content/en/docs/tasks/access-kubernetes-api/configure-aggregation-layer.md index ef5f904079..037187499a 100644 --- a/content/en/docs/tasks/access-kubernetes-api/configure-aggregation-layer.md +++ b/content/en/docs/tasks/access-kubernetes-api/configure-aggregation-layer.md @@ -246,6 +246,9 @@ spec: caBundle: ``` +The name of an APIService object must be a valid +[path segment name](/docs/concepts/overview/working-with-objects/names#path-segment-names). + #### Contacting the extension apiserver Once the Kubernetes apiserver has determined a request should be sent to a extension apiserver, diff --git a/content/en/docs/tasks/manage-daemon/rollback-daemon-set.md b/content/en/docs/tasks/manage-daemon/rollback-daemon-set.md index 7ca0a45a0f..4b1d424066 100644 --- a/content/en/docs/tasks/manage-daemon/rollback-daemon-set.md +++ b/content/en/docs/tasks/manage-daemon/rollback-daemon-set.md @@ -132,7 +132,8 @@ NAME CONTROLLER REVISION AGE ``` Each `ControllerRevision` stores the annotations and template of a DaemonSet -revision. +revision. The name of a ControllerRevision object must be a valid +[DNS subdomain name](/docs/concepts/overview/working-with-objects/names#dns-subdomain-names). `kubectl rollout undo` takes a specific `ControllerRevision` and replaces DaemonSet template with the template stored in the `ControllerRevision`. From 723e62415fb3afde8d5191339c779b581862f79f Mon Sep 17 00:00:00 2001 From: Christoph Kleineweber Date: Sat, 29 Feb 2020 03:00:39 +0100 Subject: [PATCH 100/111] Update supported environments for Kubermatic (#19380) --- content/en/docs/setup/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/setup/_index.md b/content/en/docs/setup/_index.md index 28ed6e1fcf..6c903d4e60 100644 --- a/content/en/docs/setup/_index.md +++ b/content/en/docs/setup/_index.md @@ -88,7 +88,7 @@ The following production environment solutions table lists the providers and the | [Ionos](https://www.ionos.com/enterprise-cloud) | [Ionos Managed Kubernetes](https://www.ionos.com/enterprise-cloud/managed-kubernetes) | [Ionos Enterprise Cloud](https://www.ionos.com/enterprise-cloud) | | | [Kontena Pharos](https://www.kontena.io/pharos/) | |✔| ✔ | | | | [KubeOne](https://kubeone.io/) | | ✔ | ✔ | ✔ | ✔ | ✔ | -| [Kubermatic](https://kubermatic.io/) | ✔ | ✔ | ✔ | ✔ | ✔ | | +| [Kubermatic](https://kubermatic.io/) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | [KubeSail](https://kubesail.com/) | ✔ | | | | | | [Kubespray](https://kubespray.io/#/) | | | |✔ | ✔ | ✔ | | [Kublr](https://kublr.com/) |✔ | ✔ |✔ |✔ |✔ |✔ | From 0f5510b3be2cc60ff3e042d57ac6abdf44071a99 Mon Sep 17 00:00:00 2001 From: Jacky Wu Date: Sat, 29 Feb 2020 10:02:39 +0800 Subject: [PATCH 101/111] fix: correct the kube-proxy cluster-cidr arg typo. (#19358) --- content/en/docs/concepts/services-networking/dual-stack.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/concepts/services-networking/dual-stack.md b/content/en/docs/concepts/services-networking/dual-stack.md index 0e34fa926f..81f45b5aed 100644 --- a/content/en/docs/concepts/services-networking/dual-stack.md +++ b/content/en/docs/concepts/services-networking/dual-stack.md @@ -55,7 +55,7 @@ To enable IPv4/IPv6 dual-stack, enable the `IPv6DualStack` [feature gate](/docs/ * `--feature-gates="IPv6DualStack=true"` * kube-proxy: * `--proxy-mode=ipvs` - * `--cluster-cidrs=,` + * `--cluster-cidr=,` * `--feature-gates="IPv6DualStack=true"` {{< caution >}} From 4201f7811125d31925c186f66f038b3721e1ac2e Mon Sep 17 00:00:00 2001 From: huccshen <1171593960@qq.com> Date: Sat, 29 Feb 2020 10:04:39 +0800 Subject: [PATCH 102/111] fix: correct the kube-proxy cluster-cidr arg for zh (#19375) --- content/zh/docs/concepts/services-networking/dual-stack.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/zh/docs/concepts/services-networking/dual-stack.md b/content/zh/docs/concepts/services-networking/dual-stack.md index 1bb170c06c..1fe47f6889 100644 --- a/content/zh/docs/concepts/services-networking/dual-stack.md +++ b/content/zh/docs/concepts/services-networking/dual-stack.md @@ -108,7 +108,7 @@ To enable IPv4/IPv6 dual-stack, enable the `IPv6DualStack` [feature gate](/docs/ * `--feature-gates="IPv6DualStack=true"` * kube-proxy: * `--proxy-mode=ipvs` - * `--cluster-cidrs=,` + * `--cluster-cidr=,` * `--feature-gates="IPv6DualStack=true"` {{< caution >}} From 65c92bfbe34fbcc039ce9ab7789037635d08a08a Mon Sep 17 00:00:00 2001 From: Sharjeel Aziz Date: Sat, 29 Feb 2020 20:46:39 -0500 Subject: [PATCH 103/111] Minor formatting fix (#19356) Converted bullets to paragraphs to fix formatting in Advanced features and flexibility table. Signed-off-by: sharjeelaziz --- .../extend-kubernetes/api-extension/custom-resources.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/concepts/extend-kubernetes/api-extension/custom-resources.md b/content/en/docs/concepts/extend-kubernetes/api-extension/custom-resources.md index 15f3f7e234..d0b990e0da 100644 --- a/content/en/docs/concepts/extend-kubernetes/api-extension/custom-resources.md +++ b/content/en/docs/concepts/extend-kubernetes/api-extension/custom-resources.md @@ -184,7 +184,7 @@ Aggregated APIs offer more advanced API features and customization of other feat | Custom Storage | If you need storage with a different performance mode (for example, time-series database instead of key-value store) or isolation for security (for example, encryption secrets or different | No | Yes | | Custom Business Logic | Perform arbitrary checks or actions when creating, reading, updating or deleting an object | Yes, using [Webhooks](/docs/reference/access-authn-authz/extensible-admission-controllers/#admission-webhooks). | Yes | | Scale Subresource | Allows systems like HorizontalPodAutoscaler and PodDisruptionBudget interact with your new resource | [Yes](/docs/tasks/access-kubernetes-api/extend-api-custom-resource-definitions/#scale-subresource) | Yes | -| Status Subresource |
  • Finer-grained access control: user writes spec section, controller writes status section.
  • Allows incrementing object Generation on custom resource data mutation (requires separate spec and status sections in the resource)
| [Yes](/docs/tasks/access-kubernetes-api/extend-api-custom-resource-definitions/#status-subresource) | Yes | +| Status Subresource | Allows fine-grained access control where user writes the spec section and the controller writes the status section. Allows incrementing object Generation on custom resource data mutation (requires separate spec and status sections in the resource) | [Yes](/docs/tasks/access-kubernetes-api/extend-api-custom-resource-definitions/#status-subresource) | Yes | | Other Subresources | Add operations other than CRUD, such as "logs" or "exec". | No | Yes | | strategic-merge-patch | The new endpoints support PATCH with `Content-Type: application/strategic-merge-patch+json`. Useful for updating objects that may be modified both locally, and by the server. For more information, see ["Update API Objects in Place Using kubectl patch"](/docs/tasks/run-application/update-api-object-kubectl-patch/) | No | Yes | | Protocol Buffers | The new resource supports clients that want to use Protocol Buffers | No | Yes | From 9cc37226cc7028c550a616d06021f4ae9023ffe7 Mon Sep 17 00:00:00 2001 From: huccshen <1171593960@qq.com> Date: Sun, 1 Mar 2020 09:52:40 +0800 Subject: [PATCH 104/111] fix: correct the kube-proxy cluster-cidr arg for ko (#19376) --- content/ko/docs/concepts/services-networking/dual-stack.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/ko/docs/concepts/services-networking/dual-stack.md b/content/ko/docs/concepts/services-networking/dual-stack.md index 9d58bccbd6..0c52346820 100644 --- a/content/ko/docs/concepts/services-networking/dual-stack.md +++ b/content/ko/docs/concepts/services-networking/dual-stack.md @@ -51,7 +51,7 @@ IPv4/IPv6 이중 스택을 활성화 하려면, 클러스터의 관련 구성요 * `--feature-gates="IPv6DualStack=true"` * kube-proxy: * `--proxy-mode=ipvs` - * `--cluster-cidrs=,` + * `--cluster-cidr=,` * `--feature-gates="IPv6DualStack=true"` {{< caution >}} From 9fb7a223f8556678fd46338806e691c9d60cf9b9 Mon Sep 17 00:00:00 2001 From: wwgfhf <51694849+wwgfhf@users.noreply.github.com> Date: Sun, 1 Mar 2020 10:26:40 +0800 Subject: [PATCH 105/111] Update basic-stateful-set.md (#19402) --- .../docs/tutorials/stateful-application/basic-stateful-set.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/zh/docs/tutorials/stateful-application/basic-stateful-set.md b/content/zh/docs/tutorials/stateful-application/basic-stateful-set.md index b661ea9601..2586d8600a 100644 --- a/content/zh/docs/tutorials/stateful-application/basic-stateful-set.md +++ b/content/zh/docs/tutorials/stateful-application/basic-stateful-set.md @@ -1527,7 +1527,7 @@ storage configuration, and provisioning method, to ensure that all storage is reclaimed. --> -你需要删除本教程中用到的 PersistentVolumes 的持久化存储媒体。基于你的环境、存储配置和提供方式,按照必须的步骤保证回收所有的存储。 +你需要删除本教程中用到的 PersistentVolumes 的持久化存储介质。基于你的环境、存储配置和提供方式,按照必须的步骤保证回收所有的存储。 {{% /capture %}} From 10d195690de2fc9d31c7a578cee5cdda7bdef454 Mon Sep 17 00:00:00 2001 From: Yong Zhang Date: Sun, 1 Mar 2020 15:06:41 +0800 Subject: [PATCH 106/111] =?UTF-8?q?Localize=20=E2=80=9Cemail=20address?= =?UTF-8?q?=E2=80=9D=20placeholder=20on=20home=20page=20(#19360)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- i18n/zh.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/i18n/zh.toml b/i18n/zh.toml index 41a6f0c045..c42cb6c230 100644 --- a/i18n/zh.toml +++ b/i18n/zh.toml @@ -186,3 +186,6 @@ other = "警告:" [whatsnext_heading] other = "接下来" + +[input_placeholder_email_address] +other = "电子邮件地址" \ No newline at end of file From f9fccfe33817047b72411b6511da2a5fcfb312c9 Mon Sep 17 00:00:00 2001 From: Thibault Deutsch Date: Sun, 1 Mar 2020 07:08:41 +0000 Subject: [PATCH 107/111] =?UTF-8?q?Clean=20up=20=E2=80=9CNon-preempting=20?= =?UTF-8?q?PriorityClasses=E2=80=9D=20page=20section=20(#19273)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use feature state for non-preempting PriorityClasses * PreemptionPolicy requires NonPreemptingPriority feature gate * Remove alpha qualifier from section title and decrease example heading level * Use singular of PriorityClass in the heading --- .../configuration/pod-priority-preemption.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/content/en/docs/concepts/configuration/pod-priority-preemption.md b/content/en/docs/concepts/configuration/pod-priority-preemption.md index 399f8b4e22..5c2edb1a0a 100644 --- a/content/en/docs/concepts/configuration/pod-priority-preemption.md +++ b/content/en/docs/concepts/configuration/pod-priority-preemption.md @@ -158,12 +158,9 @@ globalDefault: false description: "This priority class should be used for XYZ service pods only." ``` -### Non-preempting PriorityClasses (alpha) {#non-preempting-priority-class} +## Non-preempting PriorityClass {#non-preempting-priority-class} -1.15 adds the `PreemptionPolicy` field as an alpha feature. -It is disabled by default in 1.15, -and requires the `NonPreemptingPriority`[feature gate](/docs/reference/command-line-tools-reference/feature-gates/ -) to be enabled. +{{< feature-state for_k8s_version="1.15" state="alpha" >}} Pods with `PreemptionPolicy: Never` will be placed in the scheduling queue ahead of lower-priority pods, @@ -187,6 +184,10 @@ which will allow pods of that PriorityClass to preempt lower-priority pods If `PreemptionPolicy` is set to `Never`, pods in that PriorityClass will be non-preempting. +The use of the `PreemptionPolicy` field requires the `NonPreemptingPriority` +[feature gate](/docs/reference/command-line-tools-reference/feature-gates/) +to be enabled. + An example use case is for data science workloads. A user may submit a job that they want to be prioritized above other workloads, but do not wish to discard existing work by preempting running pods. @@ -194,7 +195,7 @@ The high priority job with `PreemptionPolicy: Never` will be scheduled ahead of other queued pods, as soon as sufficient cluster resources "naturally" become free. -#### Example Non-preempting PriorityClass +### Example Non-preempting PriorityClass ```yaml apiVersion: scheduling.k8s.io/v1 From f15d40ad38b176f9512e6b1e8334f56874da4720 Mon Sep 17 00:00:00 2001 From: huccshen <1171593960@qq.com> Date: Sun, 1 Mar 2020 15:10:40 +0800 Subject: [PATCH 108/111] Added note for capacity of source volume (#19378) --- content/zh/docs/concepts/storage/volume-pvc-datasource.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/content/zh/docs/concepts/storage/volume-pvc-datasource.md b/content/zh/docs/concepts/storage/volume-pvc-datasource.md index d39e7128eb..c740f56a5f 100644 --- a/content/zh/docs/concepts/storage/volume-pvc-datasource.md +++ b/content/zh/docs/concepts/storage/volume-pvc-datasource.md @@ -121,6 +121,14 @@ spec: name: pvc-1 ``` + + +{{< note >}} +你必须为 `spec.resources.requests.storage` 指定一个值,并且你指定的值必须大于或等于源卷的值。 +{{< /note >}} + From 1242c008a810c363e4e90239c392c702df24c0f2 Mon Sep 17 00:00:00 2001 From: Andrew Allbright Date: Sun, 1 Mar 2020 02:12:40 -0500 Subject: [PATCH 109/111] Update some instances of latin abbreviation e.g. to alternative phrases (#19182) --- content/en/docs/concepts/architecture/nodes.md | 2 +- .../docs/concepts/cluster-administration/cloud-providers.md | 2 +- .../en/docs/concepts/cluster-administration/federation.md | 2 +- content/en/docs/concepts/cluster-administration/logging.md | 2 +- content/en/docs/concepts/configuration/assign-pod-node.md | 6 +++--- .../compute-storage-net/network-plugins.md | 2 +- content/en/docs/concepts/storage/storage-classes.md | 6 +++--- .../reference/access-authn-authz/admission-controllers.md | 2 +- .../access-authn-authz/extensible-admission-controllers.md | 2 +- content/en/docs/reference/using-api/api-concepts.md | 2 +- .../tools/kubeadm/create-cluster-kubeadm.md | 2 +- .../list-all-running-container-images.md | 2 +- .../tasks/access-application-cluster/web-ui-dashboard.md | 2 +- .../custom-resource-definition-versioning.md | 2 +- .../custom-resources/custom-resource-definitions.md | 2 +- content/en/docs/tasks/administer-cluster/ip-masq-agent.md | 2 +- content/en/docs/tasks/administer-cluster/sysctl-cluster.md | 4 ++-- content/en/docs/tasks/configure-pod-container/static-pod.md | 2 +- .../configure-pod-container/translate-compose-kubernetes.md | 2 +- content/en/docs/tasks/debug-application-cluster/audit.md | 2 +- .../docs/tasks/debug-application-cluster/debug-cluster.md | 2 +- .../tasks/debug-application-cluster/logging-stackdriver.md | 2 +- 22 files changed, 27 insertions(+), 27 deletions(-) diff --git a/content/en/docs/concepts/architecture/nodes.md b/content/en/docs/concepts/architecture/nodes.md index 0b740ad46c..cf7bdac64b 100644 --- a/content/en/docs/concepts/architecture/nodes.md +++ b/content/en/docs/concepts/architecture/nodes.md @@ -157,7 +157,7 @@ controller deletes the node from its list of nodes. The third is monitoring the nodes' health. The node controller is responsible for updating the NodeReady condition of NodeStatus to ConditionUnknown when a node becomes unreachable (i.e. the node controller stops -receiving heartbeats for some reason, e.g. due to the node being down), and then later evicting +receiving heartbeats for some reason, for example due to the node being down), and then later evicting all the pods from the node (using graceful termination) if the node continues to be unreachable. (The default timeouts are 40s to start reporting ConditionUnknown and 5m after that to start evicting pods.) The node controller diff --git a/content/en/docs/concepts/cluster-administration/cloud-providers.md b/content/en/docs/concepts/cluster-administration/cloud-providers.md index 9c031807e0..b9a320192c 100644 --- a/content/en/docs/concepts/cluster-administration/cloud-providers.md +++ b/content/en/docs/concepts/cluster-administration/cloud-providers.md @@ -94,7 +94,7 @@ Different settings can be applied to a load balancer service in AWS using _annot * `service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix`: Used to specify access log s3 bucket prefix. * `service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags`: Used on the service to specify a comma-separated list of key-value pairs which will be recorded as additional tags in the ELB. For example: `"Key1=Val1,Key2=Val2,KeyNoVal1=,KeyNoVal2"`. * `service.beta.kubernetes.io/aws-load-balancer-backend-protocol`: Used on the service to specify the protocol spoken by the backend (pod) behind a listener. If `http` (default) or `https`, an HTTPS listener that terminates the connection and parses headers is created. If set to `ssl` or `tcp`, a "raw" SSL listener is used. If set to `http` and `aws-load-balancer-ssl-cert` is not used then a HTTP listener is used. -* `service.beta.kubernetes.io/aws-load-balancer-ssl-cert`: Used on the service to request a secure listener. Value is a valid certificate ARN. For more, see [ELB Listener Config](http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/elb-listener-config.html) CertARN is an IAM or CM certificate ARN, e.g. `arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012`. +* `service.beta.kubernetes.io/aws-load-balancer-ssl-cert`: Used on the service to request a secure listener. Value is a valid certificate ARN. For more, see [ELB Listener Config](http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/elb-listener-config.html) CertARN is an IAM or CM certificate ARN, for example `arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012`. * `service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled`: Used on the service to enable or disable connection draining. * `service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout`: Used on the service to specify a connection draining timeout. * `service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout`: Used on the service to specify the idle connection timeout. diff --git a/content/en/docs/concepts/cluster-administration/federation.md b/content/en/docs/concepts/cluster-administration/federation.md index 7900b53d27..e26aef3fa8 100644 --- a/content/en/docs/concepts/cluster-administration/federation.md +++ b/content/en/docs/concepts/cluster-administration/federation.md @@ -140,7 +140,7 @@ Reasons to prefer fewer clusters per availability zone are: - improved bin packing of Pods in some cases with more nodes in one cluster (less resource fragmentation). - reduced operational overhead (though the advantage is diminished as ops tooling and processes mature). - - reduced costs for per-cluster fixed resource costs, e.g. apiserver VMs (but small as a percentage + - reduced costs for per-cluster fixed resource costs, for example apiserver VMs (but small as a percentage of overall cluster cost for medium to large clusters). Reasons to have multiple clusters include: diff --git a/content/en/docs/concepts/cluster-administration/logging.md b/content/en/docs/concepts/cluster-administration/logging.md index 2c1ab5f3fe..e464a2869e 100644 --- a/content/en/docs/concepts/cluster-administration/logging.md +++ b/content/en/docs/concepts/cluster-administration/logging.md @@ -76,7 +76,7 @@ should set up a solution to address that. For example, in Kubernetes clusters, deployed by the `kube-up.sh` script, there is a [`logrotate`](https://linux.die.net/man/8/logrotate) tool configured to run each hour. You can also set up a container runtime to -rotate application's logs automatically, e.g. by using Docker's `log-opt`. +rotate application's logs automatically, for example by using Docker's `log-opt`. In the `kube-up.sh` script, the latter approach is used for COS image on GCP, and the former approach is used in any other environment. In both cases, by default rotation is configured to take place when log file exceeds 10MB. diff --git a/content/en/docs/concepts/configuration/assign-pod-node.md b/content/en/docs/concepts/configuration/assign-pod-node.md index 2c5becff54..19f33c47e8 100644 --- a/content/en/docs/concepts/configuration/assign-pod-node.md +++ b/content/en/docs/concepts/configuration/assign-pod-node.md @@ -17,7 +17,7 @@ There are several ways to do this, and the recommended approaches all use [label selectors](/docs/concepts/overview/working-with-objects/labels/) to make the selection. Generally such constraints are unnecessary, as the scheduler will automatically do a reasonable placement (e.g. spread your pods across nodes, not place the pod on a node with insufficient free resources, etc.) -but there are some circumstances where you may want more control on a node where a pod lands, e.g. to ensure +but there are some circumstances where you may want more control on a node where a pod lands, for example to ensure that a pod ends up on a machine with an SSD attached to it, or to co-locate pods from two different services that communicate a lot into the same availability zone. @@ -176,7 +176,7 @@ Y is expressed as a LabelSelector with an optional associated list of namespaces (and therefore the labels on pods are implicitly namespaced), a label selector over pod labels must specify which namespaces the selector should apply to. Conceptually X is a topology domain like node, rack, cloud provider zone, cloud provider region, etc. You express it using a `topologyKey` which is the -key for the node label that the system uses to denote such a topology domain, e.g. see the label keys listed above +key for the node label that the system uses to denote such a topology domain; for example, see the label keys listed above in the section [Interlude: built-in node labels](#built-in-node-labels). {{< note >}} @@ -366,7 +366,7 @@ Some of the limitations of using `nodeName` to select nodes are: some cases may be automatically deleted. - If the named node does not have the resources to accommodate the pod, the pod will fail and its reason will indicate why, - e.g. OutOfmemory or OutOfcpu. + for example OutOfmemory or OutOfcpu. - Node names in cloud environments are not always predictable or stable. diff --git a/content/en/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins.md b/content/en/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins.md index 3cb5f3ffa8..a9b76cdd51 100644 --- a/content/en/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins.md +++ b/content/en/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins.md @@ -154,7 +154,7 @@ most network plugins. Where needed, you can specify the MTU explicitly with the `network-plugin-mtu` kubelet option. For example, on AWS the `eth0` MTU is typically 9001, so you might specify `--network-plugin-mtu=9001`. If you're using IPSEC you -might reduce it to allow for encapsulation overhead e.g. `--network-plugin-mtu=8873`. +might reduce it to allow for encapsulation overhead; for example: `--network-plugin-mtu=8873`. This option is provided to the network-plugin; currently **only kubenet supports `network-plugin-mtu`**. diff --git a/content/en/docs/concepts/storage/storage-classes.md b/content/en/docs/concepts/storage/storage-classes.md index 89788349b8..5a55665db3 100644 --- a/content/en/docs/concepts/storage/storage-classes.md +++ b/content/en/docs/concepts/storage/storage-classes.md @@ -350,7 +350,7 @@ parameters: contains user password to use when talking to Gluster REST service. These parameters are optional, empty password will be used when both `secretNamespace` and `secretName` are omitted. The provided secret must have - type `"kubernetes.io/glusterfs"`, e.g. created in this way: + type `"kubernetes.io/glusterfs"`, for example created in this way: ``` kubectl create secret generic heketi-secret \ @@ -514,7 +514,7 @@ parameters: same as `adminId`. * `userSecretName`: The name of Ceph Secret for `userId` to map RBD image. It must exist in the same namespace as PVCs. This parameter is required. - The provided secret must have type "kubernetes.io/rbd", e.g. created in this + The provided secret must have type "kubernetes.io/rbd", for example created in this way: ```shell @@ -561,7 +561,7 @@ parameters: * `adminSecretName`: secret that holds information about the Quobyte user and the password to authenticate against the API server. The provided secret must have type "kubernetes.io/quobyte" and the keys `user` and `password`, - e.g. created in this way: + for example: ```shell kubectl create secret generic quobyte-admin-secret \ diff --git a/content/en/docs/reference/access-authn-authz/admission-controllers.md b/content/en/docs/reference/access-authn-authz/admission-controllers.md index 2ab54051a4..3d85194ed7 100644 --- a/content/en/docs/reference/access-authn-authz/admission-controllers.md +++ b/content/en/docs/reference/access-authn-authz/admission-controllers.md @@ -732,7 +732,7 @@ For Kubernetes 1.9 and earlier, we recommend running the following set of admiss ``` * It's worth reiterating that in 1.9, these happen in a mutating phase -and a validating phase, and that e.g. `ResourceQuota` runs in the validating +and a validating phase, and that for example `ResourceQuota` runs in the validating phase, and therefore is the last admission controller to run. `MutatingAdmissionWebhook` appears before it in this list, because it runs in the mutating phase. diff --git a/content/en/docs/reference/access-authn-authz/extensible-admission-controllers.md b/content/en/docs/reference/access-authn-authz/extensible-admission-controllers.md index 4131a79df8..4da9bc951c 100644 --- a/content/en/docs/reference/access-authn-authz/extensible-admission-controllers.md +++ b/content/en/docs/reference/access-authn-authz/extensible-admission-controllers.md @@ -1050,7 +1050,7 @@ to turn up in a new cluster. The scheme must be "https"; the URL must begin with "https://". -Attempting to use a user or basic auth e.g. "user:password@" is not allowed. +Attempting to use a user or basic auth (for example "user:password@") is not allowed. Fragments ("#...") and query parameters ("?...") are also not allowed. Here is an example of a mutating webhook configured to call a URL diff --git a/content/en/docs/reference/using-api/api-concepts.md b/content/en/docs/reference/using-api/api-concepts.md index 776715c8a2..8c7464d694 100644 --- a/content/en/docs/reference/using-api/api-concepts.md +++ b/content/en/docs/reference/using-api/api-concepts.md @@ -578,7 +578,7 @@ A number of markers were added in Kubernetes 1.16 and 1.17, to allow API develop | Golang marker | OpenAPI extension | Accepted values | Description | Introduced in | |---|---|---|---|---| | `//+listType` | `x-kubernetes-list-type` | `atomic`/`set`/`map` | Applicable to lists. `atomic` and `set` apply to lists with scalar elements only. `map` applies to lists of nested types only. If configured as `atomic`, the entire list is replaced during merge; a single manager manages the list as a whole at any one time. If `granular`, different managers can manage entries separately. | 1.16 | -| `//+listMapKeys` | `x-kubernetes-list-map-keys` | Slice of map keys that uniquely identify entries e.g. `["port", "protocol"]` | Only applicable when `+listType=map`. A slice of strings whose values in combination must uniquely identify list entries. | 1.16 | +| `//+listMapKeys` | `x-kubernetes-list-map-keys` | Slice of map keys that uniquely identify entries for example `["port", "protocol"]` | Only applicable when `+listType=map`. A slice of strings whose values in combination must uniquely identify list entries. | 1.16 | | `//+mapType` | `x-kubernetes-map-type` | `atomic`/`granular` | Applicable to maps. `atomic` means that the map can only be entirely replaced by a single manager. `granular` means that the map supports separate managers updating individual fields. | 1.17 | | `//+structType` | `x-kubernetes-map-type` | `atomic`/`granular` | Applicable to structs; otherwise same usage and OpenAPI annotation as `//+mapType`.| 1.17 | diff --git a/content/en/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm.md b/content/en/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm.md index 2c978b0653..889b85f64d 100644 --- a/content/en/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm.md +++ b/content/en/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm.md @@ -403,7 +403,7 @@ for `kubeadm`. ### Control plane node isolation By default, your cluster will not schedule Pods on the control-plane node for security -reasons. If you want to be able to schedule Pods on the control-plane node, e.g. for a +reasons. If you want to be able to schedule Pods on the control-plane node, for example for a single-machine Kubernetes cluster for development, run: ```bash diff --git a/content/en/docs/tasks/access-application-cluster/list-all-running-container-images.md b/content/en/docs/tasks/access-application-cluster/list-all-running-container-images.md index caf20d7f2e..8b4480de2f 100644 --- a/content/en/docs/tasks/access-application-cluster/list-all-running-container-images.md +++ b/content/en/docs/tasks/access-application-cluster/list-all-running-container-images.md @@ -63,7 +63,7 @@ The jsonpath is interpreted as follows: - `.image`: get the image {{< note >}} -When fetching a single Pod by name, e.g. `kubectl get pod nginx`, +When fetching a single Pod by name, for example `kubectl get pod nginx`, the `.items[*]` portion of the path should be omitted because a single Pod is returned instead of a list of items. {{< /note >}} diff --git a/content/en/docs/tasks/access-application-cluster/web-ui-dashboard.md b/content/en/docs/tasks/access-application-cluster/web-ui-dashboard.md index 9b5e997782..ecda7709cf 100644 --- a/content/en/docs/tasks/access-application-cluster/web-ui-dashboard.md +++ b/content/en/docs/tasks/access-application-cluster/web-ui-dashboard.md @@ -113,7 +113,7 @@ track=stable - **Image Pull Secret**: In case the specified Docker container image is private, it may require [pull secret](/docs/concepts/configuration/secret/) credentials. - Dashboard offers all available secrets in a dropdown list, and allows you to create a new secret. The secret name must follow the DNS domain name syntax, e.g. `new.image-pull.secret`. The content of a secret must be base64-encoded and specified in a [`.dockercfg`](/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod) file. The secret name may consist of a maximum of 253 characters. + Dashboard offers all available secrets in a dropdown list, and allows you to create a new secret. The secret name must follow the DNS domain name syntax, for example `new.image-pull.secret`. The content of a secret must be base64-encoded and specified in a [`.dockercfg`](/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod) file. The secret name may consist of a maximum of 253 characters. In case the creation of the image pull secret is successful, it is selected by default. If the creation fails, no secret is applied. diff --git a/content/en/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definition-versioning.md b/content/en/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definition-versioning.md index f730fb3660..184e870fc3 100644 --- a/content/en/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definition-versioning.md +++ b/content/en/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definition-versioning.md @@ -502,7 +502,7 @@ to turn up in a new cluster. The scheme must be "https"; the URL must begin with "https://". -Attempting to use a user or basic auth e.g. "user:password@" is not allowed. +Attempting to use a user or basic auth (for example "user:password@") is not allowed. Fragments ("#...") and query parameters ("?...") are also not allowed. Here is an example of a conversion webhook configured to call a URL diff --git a/content/en/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions.md b/content/en/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions.md index b2d5703b1c..dd96f2d6d6 100644 --- a/content/en/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions.md +++ b/content/en/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions.md @@ -366,7 +366,7 @@ Structural schemas are a requirement for `apiextensions.k8s.io/v1`, and disables {{< feature-state state="stable" for_kubernetes_version="1.16" >}} -CustomResourceDefinitions traditionally store any (possibly validated) JSON as is in etcd. This means that unspecified fields (if there is a [OpenAPI v3.0 validation schema](/docs/tasks/access-kubernetes-api/extend-api-custom-resource-definitions/#validation) at all) are persisted. This is in contrast to native Kubernetes resources like e.g. a pod where unknown fields are dropped before being persisted to etcd. We call this "pruning" of unknown fields. +CustomResourceDefinitions traditionally store any (possibly validated) JSON as is in etcd. This means that unspecified fields (if there is a [OpenAPI v3.0 validation schema](/docs/tasks/access-kubernetes-api/extend-api-custom-resource-definitions/#validation) at all) are persisted. This is in contrast to native Kubernetes resources such as a pod where unknown fields are dropped before being persisted to etcd. We call this "pruning" of unknown fields. {{< tabs name="CustomResourceDefinition_pruning" >}} {{% tab name="apiextensions.k8s.io/v1" %}} 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 3cce9c7153..bdc871ddd9 100644 --- a/content/en/docs/tasks/administer-cluster/ip-masq-agent.md +++ b/content/en/docs/tasks/administer-cluster/ip-masq-agent.md @@ -37,7 +37,7 @@ The agent configuration file must be written in YAML or JSON syntax, and may con * **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:** An interval at which the agent attempts to reload config from disk. e.g. '30s' where 's' is seconds, 'ms' is milliseconds etc... +* **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... 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: diff --git a/content/en/docs/tasks/administer-cluster/sysctl-cluster.md b/content/en/docs/tasks/administer-cluster/sysctl-cluster.md index 9f341d046f..5e57c18379 100644 --- a/content/en/docs/tasks/administer-cluster/sysctl-cluster.md +++ b/content/en/docs/tasks/administer-cluster/sysctl-cluster.md @@ -72,9 +72,9 @@ cluster admin on a per-node basis. Pods with disabled unsafe sysctls will be scheduled, but will fail to launch. With the warning above in mind, the cluster admin can allow certain _unsafe_ -sysctls for very special situations like e.g. high-performance or real-time +sysctls for very special situations such as high-performance or real-time application tuning. _Unsafe_ sysctls are enabled on a node-by-node basis with a -flag of the kubelet, e.g.: +flag of the kubelet; for example: ```shell kubelet --allowed-unsafe-sysctls \ diff --git a/content/en/docs/tasks/configure-pod-container/static-pod.md b/content/en/docs/tasks/configure-pod-container/static-pod.md index 320d800dc9..fc31526348 100644 --- a/content/en/docs/tasks/configure-pod-container/static-pod.md +++ b/content/en/docs/tasks/configure-pod-container/static-pod.md @@ -63,7 +63,7 @@ For example, this is how to start a simple web server as a static Pod: ssh my-node1 ``` -2. Choose a directory, say `/etc/kubelet.d` and place a web server Pod definition there, e.g. `/etc/kubelet.d/static-web.yaml`: +2. Choose a directory, say `/etc/kubelet.d` and place a web server Pod definition there, for example `/etc/kubelet.d/static-web.yaml`: ```shell # Run this command on the node where kubelet is running diff --git a/content/en/docs/tasks/configure-pod-container/translate-compose-kubernetes.md b/content/en/docs/tasks/configure-pod-container/translate-compose-kubernetes.md index 4d0521722a..847d76f25c 100644 --- a/content/en/docs/tasks/configure-pod-container/translate-compose-kubernetes.md +++ b/content/en/docs/tasks/configure-pod-container/translate-compose-kubernetes.md @@ -580,7 +580,7 @@ If you want to create normal pods without controllers you can use `restart` cons The controller object could be `deployment` or `replicationcontroller`, etc. {{< /note >}} -For e.g. `pival` service will become pod down here. This container calculated value of `pi`. +For example, the `pival` service will become pod down here. This container calculated value of `pi`. ```yaml version: '2' diff --git a/content/en/docs/tasks/debug-application-cluster/audit.md b/content/en/docs/tasks/debug-application-cluster/audit.md index 2c769eb933..ed95d353ac 100644 --- a/content/en/docs/tasks/debug-application-cluster/audit.md +++ b/content/en/docs/tasks/debug-application-cluster/audit.md @@ -272,7 +272,7 @@ to turn up in a new cluster. The scheme must be "https"; the URL must begin with "https://". -Attempting to use a user or basic auth e.g. "user:password@" is not allowed. +Attempting to use a user or basic auth (for example "user:password@") is not allowed. Fragments ("#...") and query parameters ("?...") are also not allowed. Here is an example of a webhook configured to call a URL diff --git a/content/en/docs/tasks/debug-application-cluster/debug-cluster.md b/content/en/docs/tasks/debug-application-cluster/debug-cluster.md index 4e95d82905..ae56c42411 100644 --- a/content/en/docs/tasks/debug-application-cluster/debug-cluster.md +++ b/content/en/docs/tasks/debug-application-cluster/debug-cluster.md @@ -55,7 +55,7 @@ This is an incomplete list of things that could go wrong, and how to adjust your - Network partition within cluster, or between cluster and users - Crashes in Kubernetes software - Data loss or unavailability of persistent storage (e.g. GCE PD or AWS EBS volume) - - Operator error, e.g. misconfigured Kubernetes software or application software + - Operator error, for example misconfigured Kubernetes software or application software ### Specific scenarios: diff --git a/content/en/docs/tasks/debug-application-cluster/logging-stackdriver.md b/content/en/docs/tasks/debug-application-cluster/logging-stackdriver.md index d075944516..a60ceeedfb 100644 --- a/content/en/docs/tasks/debug-application-cluster/logging-stackdriver.md +++ b/content/en/docs/tasks/debug-application-cluster/logging-stackdriver.md @@ -362,7 +362,7 @@ you want to add Kafka sink for messages from a particular container for addition You can re-use the default [container image sources](https://git.k8s.io/contrib/fluentd/fluentd-gcp-image) with minor changes: -* Change Makefile to point to your container repository, e.g. `PREFIX=gcr.io/`. +* Change Makefile to point to your container repository, for example `PREFIX=gcr.io/`. * Add your dependency to the Gemfile, for example `gem 'fluent-plugin-kafka'`. Then run `make build push` from this directory. After updating `DaemonSet` to pick up the From 54162359577ad27d44815b21b7856bfadf45cd08 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Sun, 1 Mar 2020 12:06:40 +0300 Subject: [PATCH 110/111] Translate Localizing Kubernetes Documentation page into Russian (#19173) --- content/ru/docs/contribute/localization.md | 286 +++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 content/ru/docs/contribute/localization.md diff --git a/content/ru/docs/contribute/localization.md b/content/ru/docs/contribute/localization.md new file mode 100644 index 0000000000..4706ff4e90 --- /dev/null +++ b/content/ru/docs/contribute/localization.md @@ -0,0 +1,286 @@ +--- +title: Локализация документации Kubernetes +content_template: templates/concept +card: + name: contribute + weight: 30 + title: Перевод документации +--- + +{{% capture overview %}} + +На этой странице рассказывается, как [локализовать](https://blog.mozilla.org/l10n/2011/12/14/i18n-vs-l10n-whats-the-diff/) документацию на разные языки. + +{{% /capture %}} + +{{% capture body %}} + +## Начало работы + +Из-за того, что участники не могут одобрять собственные пулреквесты, нужно как минимум два участника для инициализации локализацию. + +Все команды по локализации должны быть самодостаточными. Это означает, что мы с радостью разместим вашу работу, но мы не можем сделать перевод за вас. + +### Определение двухбуквенного кода языка + +Первым делом ознакомьтесь со [стандартом ISO 639-1](https://www.loc.gov/standards/iso639-2/php/code_list.php), чтобы найти двухбуквенный код страны для вашей локализации. Например, двухбуквенный код для корейского языка будет `ko`. + +### Создание копии репозитория + +Для начала [создайте собственную копию репозитория](/ru/docs/contribute/start/#улучшение-существующего-текста) оригинального репозитория [kubernetes/website](https://github.com/kubernetes/website). + +Затем клонируйте свою копию репозитория и перейдите в неё с помощью команды `cd`: + +```shell +git clone https://github.com//website +cd website +``` + +### Создание пулреквеста + +Далее [откройте пулреквест](/ru/docs/contribute/start/#отправка-пулреквеста) (PR) с локализацией в репозиторий `kubernetes/website`. + +Для того, чтобы ваш пулреквест был одобрен, он должен содержать [необходимый минимум контента](#необходимый-минимум-контента). + +В качестве примера добавления новой локализации, изучите PR, который добавляет [документацию на французском](https://github.com/kubernetes/website/pull/12548). + +### Вступление в GitHub-организацию Kubernetes + +Как только, как вы открыли PR с локализацией, вы можете стать членом организации Kubernetes на GitHub. Каждый член команды должен подать [запрос на членство в организации](https://github.com/kubernetes/org/issues/new/choose) в репозитории `kubernetes/org`. + +### Добавление команды локализации на GitHub + +Теперь нужно добавить вашу команду локализации Kubernetes в файл [`sig-docs/teams.yaml`](https://github.com/kubernetes/org/blob/master/config/kubernetes/sig-docs/teams.yaml). Для примера добавления команды локализации можете посмотреть PR, добавляющий [испанскую команду локализации](https://github.com/kubernetes/org/pull/685). + +Члены `@kubernetes/sig-docs-**-owners` — могут одобрять PR, которые изменяют файлы внутри (и только там) директории с локализацией: `/content/**/`. + +Для каждой локализации группа `@kubernetes/sig-docs-**-reviews` служит для автоматизации выбора проверяющих новых PR. + +Члены `@kubernetes/website-maintainers` могут создавать новые ветки для координации работ по переводу. + +Члены `@kubernetes/website-milestone-maintainers` могут использовать [Prow-команду](https://prow.k8s.io/command-help) `/milestone` для контрольных точек для ишью или PR. + +### Настройка рабочего процесса + +Затем добавьте собственную GitHub-метку для вашей локализации в репозиторий `kubernetes/test-infra`. Метка позволяет фильтровать ишью и пулреквесты по конкретному языку. + +Смотрите пример добавления [метки для итальянского языка](https://github.com/kubernetes/test-infra/pull/11316). + +### Поиск сообщества + +Сообщите участниками группы Kubernetes SIG Docs о вашем намерении перевода документации! Подключайтесь к [Slack-каналу SIG Docs](https://kubernetes.slack.com/messages/C1J0BPD2M/). Остальные команды по локализации с радостью помогут вам начать и ответят на любые вопросы. + +Вы также можете создать Slack-канал для своей локализации в репозитории `kubernetes/community`. Для примера посмотрите PR с [добавлением Slack-канала для индонезийского и португальского языков](https://github.com/kubernetes/community/pull/3605). + +## Необходимый минимум контента + +### Изменение конфигурации сайта + +Сайт Kubernetes использует использует фреймворк Hugo. Конфигурация сайта у Hugo находится в файле [`config.toml`](https://github.com/kubernetes/website/tree/master/config.toml). Для поддержки новой локализации вам нужно отредактировать файл `config.toml`. + +Добавьте блок с конфигурацией для нового языка в `config.toml` после существующего блока `[languages]`. Например, конфигурация для немецкой локализации будет выглядить так: + +```toml +[languages.de] +title = "Kubernetes" +description = "Produktionsreife Container-Verwaltung" +languageName = "Deutsch" +contentDir = "content/de" +weight = 3 +``` + +При выбора значения для параметра `weight` в блока найдите языковой блок с наибольшим значением и прибавьте к нему 1. + +Для получения дополнительной информации о многоязычной поддержке в Hugo посмотрите страницу "[Multilingual Mode](https://gohugo.io/content-management/multilingual/)". + +### Добавление директории для локализации + +Добавьте директорию для вашего языка в директорию [`content`](https://github.com/kubernetes/website/tree/master/content) репозитория. Например, двухбуквенный код для немецкого будет `de`: + +```shell +mkdir content/de +``` + +### Перевод норм поведения сообщества + +Откройте PR в репозитории [`cncf/foundation`](https://github.com/cncf/foundation/tree/master/code-of-conduct-languages) и добавьте перевод норм поведения на своём языке. + +### Добавление перевода для файла README + +Чтобы помочь другим участников локализации добавьте новый файл [`README-**.md`](https://help.github.com/articles/about-readmes/) в корневую директорию k/website, где `**` означает двухбуквенный код языка. Например, немецкий файл README будет именоваться как `README-de.md`. + +Подготовьте рекомендации для участников в файле для конкретной локализации `README-**.md`. В этом файле должна быть точно такая же информация, что и в оригинальном README.md ту же информацию, включая также: + +- Контактное лицо проекта локализации +- Любая другая информация, относящаяся к локализации + +После создания перевода файла README добавьте ссылку на файл в основной английский файл `README.md` и добавьте контактную информацию на английском языке. Вы можете указать логин на GitHub, адрес электронной почты, Slack-канал или какой-нибудь способ связи. Вам также нужно добавить ссылку на перевод норм поведения в сообществе. + +### Настройка файлов OWNERS + +Для определения роли каждого пользователя, участвующего в локализации, создайте файл `OWNERS` в директории языка, указав в нём следующие секции: + +- **reviewers**: список Kubernetes-команд с ролями рецензентов, в данном случае команда `sig-docs-**-reviews` будет создана в разделе [Добавление команды локализации на GitHub](#добавление-команды-локализации-на-github). +- **approvers**: список Kubernetes-команд с ролями утверждающих, в данном случае команда `sig-docs-**-owners` будет создана в разделе [Добавление команды локализации на GitHub](#добавление-команды-локализации-на-github). +- **labels**: список GitHub-меток, которые будут автоматически добавляться к PR, в данном случае метка языка будет создана в разделе [Настройка рабочего процесса](#настройка-рабочего-процесса). + +Дополнительную информацию о файле `OWNERS` вы можете получить по ссылке [go.k8s.io/owners](https://go.k8s.io/owners). + +[Испанский файл OWNERS](https://git.k8s.io/website/content/es/OWNERS) с кодом языка `es` выглядит следующим образом: + +```yaml +# See the OWNERS docs at https://go.k8s.io/owners + +# This is the localization project for Spanish. +# Teams and members are visible at https://github.com/orgs/kubernetes/teams. + +reviewers: +- sig-docs-es-reviews + +approvers: +- sig-docs-es-owners + +labels: +- language/es +``` + +После добавления файла `OWNERS` в определенном языке нужно обновить [корневой файл `OWNERS_ALIASES`](https://git.k8s.io/website/OWNERS_ALIASES), добавив новые команды локализации Kubernetes — `sig-docs-**-owners` и `sig-docs-**-reviews`. + +Для каждой команды добавьте список GitHub-пользователей из раздела [Добавление команды локализации на GitHub](#добавление-команды-локализации-на-github), перечислите их в алфавитном порядке. + +```diff +--- a/OWNERS_ALIASES ++++ b/OWNERS_ALIASES +@@ -48,6 +48,14 @@ aliases: + - stewart-yu + - xiangpengzhao + - zhangxiaoyu-zidif ++ sig-docs-es-owners: # Admins for Spanish content ++ - alexbrand ++ - raelga ++ sig-docs-es-reviews: # PR reviews for Spanish content ++ - alexbrand ++ - electrocucaracha ++ - glo-pena ++ - raelga + sig-docs-fr-owners: # Admins for French content + - perriea + - remyleone +``` + +## Перевод контента + +Локализация *всей* документации Kubernetes — колоссальная задача. Вполне нормально начать переводить что-то небольшое, а затем со временем делать перевод больших страниц. + +Как минимум, все локализации должны включать: + +Описание | URL-адреса +-----|----- +Главная | [Все заголовки и подзаголовки URL-адресов](/ru/docs/home/) +Установка | [Все заголовки и подзаголовки URL-адресов](/ru/docs/setup/) +Руководства | [Основы Kubernetes](/ru/docs/tutorials/kubernetes-basics/), [Привет, Minikube](/ru/docs/tutorials/stateless-application/hello-minikube/) +Надписи на сайте | [Все надписи сайта в собственном TOML-файле](https://github.com/kubernetes/website/tree/master/i18n) + +Переведенные файлы должны находиться в собственной директории `content/**/`, но в во всём остальном должны быть такие, как и оригинал на английском. Например, чтобы подготовить [Основы Kubernetes](/ru/docs/tutorials/kubernetes-basics/) для перевода на немецкий язык, создайте поддиректорию в директории `content/de/` и скопируйте туда оригинальный английский файл: + +```shell +mkdir -p content/de/docs/tutorials +cp content/en/docs/tutorials/kubernetes-basics.md content/de/docs/tutorials/kubernetes-basics.md +``` + +С помощью соответствующих инструментов можно ускорить процесс перевода. Например, у некоторых редакторов есть плагины для быстрого перевода текста. + +{{< caution >}} +Использование только машинного перевода не будет соответствовать минимальному уровню качества и поэтому такой перевод требует тщательного ручного рассмотрения для соблюдения стандарта качества. +{{< /caution >}} + +To ensure accuracy in grammar and meaning, members of your localization team should carefully review all machine-generated translations before publishing. + +### Исходные файлы + +Локализация должна исходить из самой последней версии оригинальной документации — {{< latest-version >}}. + +Для того, чтобы получить исходные файлы последней версии: + +1. Перейдите в репозиторий сайта Kubernetes по адресу https://github.com/kubernetes/website. +2. Выберите ветку `release-1.X` самой последней версии. + +Текущая последняя версия {{< latest-version >}}, поэтому веткой для этого релиза будет [`{{< release-branch >}}`](https://github.com/kubernetes/website/tree/{{< release-branch >}}). + +### Сообщения на сайте в i18n/ + +Локализации должны включать содержимое файла [`i18n/en.toml`](https://github.com/kubernetes/website/blob/master/i18n/en.toml) в новый языковой файл. В качестве примера рассмотрим немецкую локализацию: `i18n/de.toml`. + +Добавьте новый файл локализации в `i18n/`. Например, для немецкой локализации (`de`): + +```shell +cp i18n/en.toml i18n/de.toml +``` + +Затем переведите значение каждого сообщения: + +```TOML +[docs_label_i_am] +other = "ICH BIN..." +``` + +Локализация сообщений сайта позволяет изменить сообщения, используемые на всём сайте, к примеру, текст авторских прав в футере на каждой странице. + +### Глоссарий и руководство по оформления для языка + +У некоторых языковых команд есть собственные руководства по оформлению и глоссарий. Например, посмотрите [руководство корейской локализации](/ko/docs/contribute/localization_ko/). + +## Стратегия работы с ветками + +Работа в проектах локализации осуществляется посредством совместных усилий, поэтому мы приветствуем решение команды работать в общих ветках разработки. + +Совместная работа в рабочих ветках может быть организована следующим образом: + +1. Член команды [@kubernetes/website-maintainers](https://github.com/orgs/kubernetes/teams/website-maintainers) создает ветку из оригинальной ветки на https://github.com/kubernetes/website. + + После того, как вы [добавите свою команду локализации](#добавление-команды-локализации-на-github) в репозиторий [`kubernetes/org`](https://github.com/kubernetes/org), ваши утверждающие из группы будет присоединены к команде `@kubernetes/website-maintainers`. + + Мы рекомендуем следующую схему именования веток: + + `dev-<оригинальная версия>-<код языка>.<контрольная точка команды>` + + Например, утверждающий в немецкой группе локализации открывает рабочую ветку `dev-1.12-de.1` непосредственно в репозитории kubernetes/website из ветки для Kubernetes v1.12. + +2. Остальные участники создают новые ветки с изменениями на основе рабочей ветки. + + Например, участник немецкой группы локализации открывает пулреквест с изменениями в `kubernetes:dev-1.12-de.1` из `username:local-branch-name`. + +3. Утверждающий проверяет изменения и объединяют ветки в рабочую веткой. + +4. Периодически утверждающий объединяет рабочую ветку в оригинальную ветку, открывая и принимая новый пулреквест. Не забудьте объединить (squash) коммиты перед слиянием пулреквеста. + +Повторяйте шаги 1-4 до тех пор, пока не будет завершена локализация. Например, по мере работы над немецким переводом, рабочие ветки будут меняться: `dev-1.12-de.2`, `dev-1.12-de.3` и т.д. + +Команды должны объединять переведённый контент в ту же ветку выпуска, из которой она была создана. Например, рабочая ветка, созданная из версии {{< release-branch >}}, должна сливаться с веткой версии 1.17. + +Утверждающему следует поддерживать рабочую веку в актуальном состоянии в соответствии с оригинальной веткой, разрешая конфликты при слиянии. Чем дольше существует рабочая ветки, тем больше потребуется сил для ее поддержки. Поэтому лучше как можно быстрее сливать рабочую ветку и открывать новую, а не поддерживать только одну-единственную в течение длительного времени. + +В начале каждой контрольной точки команды полезно открыть ишью для сравнения изменений между предыдущей веткой и текущей рабочей веткой. + +Хотя только утверждающие могут открывать новую рабочую ветку и сливать пулреквесты, но любой может открыть пулреквест с новой веткой, которая может быть рабочей для команды. Никаких специальных разрешений для этого не требуется. + +Для получения дополнительной информации о работе с копиями или непосредственно с оригинальным репозиторией смотрите раздел по [созданию и клонированию копии репозитория](#создание-копии-репозитория). + +## Участие в работе над оригинальным контентом + +SIG Docs приветствует [участие и дополнения](/ru/docs/contribute/intermediate#локализация-контента) в английскую документацию. + +## Помощь для существующей локализации + +Вы также можете добавлять или улучшать контент в уже существующей локализации. Обратитесь к соответствующему [Slack-каналу](https://kubernetes.slack.com/messages/C1J0BPD2M/) для этого и начинайте помогать через PR. + +{{% /capture %}} + +{{% capture whatsnext %}} + +Как только локализация будет соответствовать требованиям установленного рабочего процесса и содержать требуемый минимум контента, группа SIG Docs: + +- Добавит язык на сайт +- Сообщит о новой локализации на каналах [Cloud Native Computing Foundation](https://www.cncf.io/about/) (CNCF), включая [блог Kubernetes](https://kubernetes.io/blog/). + +{{% /capture %}} From 006643f9d6745cfc4cd3ef8c8e5c1a06431c754d Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Sun, 1 Mar 2020 12:12:41 +0300 Subject: [PATCH 111/111] Translate Intermediate contributing page into Russian (#19215) --- content/ru/docs/contribute/intermediate.md | 606 +++++++++++++++++++++ 1 file changed, 606 insertions(+) create mode 100644 content/ru/docs/contribute/intermediate.md diff --git a/content/ru/docs/contribute/intermediate.md b/content/ru/docs/contribute/intermediate.md new file mode 100644 index 0000000000..2658dc3500 --- /dev/null +++ b/content/ru/docs/contribute/intermediate.md @@ -0,0 +1,606 @@ +--- +title: Участие для продолжающих +slug: intermediate +content_template: templates/concept +weight: 20 +card: + name: contribute + weight: 50 +---1 + +{{% capture overview %}} + +На этой странице предполагается, что вы изучили и понимаете задачи на странице [Начало участия](/ru/docs/contribute/start/) и теперь готовы узнать о других способах внести свой вклад. + +{{< note >}} +Некоторые задачи требуют использование Git-клиента из командной строки и других инструментов. +{{< /note >}} + +{{% /capture %}} + +{{% capture body %}} + +Теперь, когда вы уже знаете кое-что и приняли участие в документации Kubernetes, как описано в теме [Начало участия](/ru/docs/contribute/start/), вы можете пойти ещё дальше. Далее пойдут задачи, предусматривающие наличие и желание получить глубокие знания по следующим темам: + +- Концепции Kubernetes +- Рабочие процессы документации Kubernetes +- Поиск нужной информации о будущих возможностях Kubernetes +- Сильные аналитические навыки в целом + +Эти задачи не такие последовательные, как задачи для начинающих. Поэтому мы не ожидаем, что кто-то в одиночку будет постоянно заниматься всеми ими. + +## Знакомство с Prow + +[Prow](https://github.com/kubernetes/test-infra/blob/master/prow/README.md) — это система CI/CD, использующая Kubernetes, которая выполняет задания с пулреквестами (PR). Prow с помощью команд, похожих на те, что есть в чатботах, даёт возможность обрабатывать действия в организации Kubernetes на GitHub. Вы можете выполнять целый ряд действий, такие как добавление и удаление меток, закрытие заявок и назначение утверждающего. Введите Prow-команду в поле для комментария в формате `/`. Некоторые популярные команды: + +- `/lgtm` (looks good to me): добавляет метку `lgtm`, которая сообщает, что рецензент проверил PR +- `/approve`: одобряет PR так, чтобы он мог быть принят (эта команда работает только для утверждающих) +- `/assign`: назначает проверяющего на PR +- `/close`: закрывает ишью или PR +- `/hold`: добавляет метку `do-not-merge/hold`, которая означает, что PR не может быть автоматически принят +- `/hold cancel`: удаляет метку `do-not-merge/hold` + +{{% note %}} +Не все команды работают для каждого пользователя. Бот Prow сообщит вам, если вы пытаетесь выполнить команду, не разрешенную для вашего уровня. +{{% /note %}} + +Детально изучите [список команд Prow](https://prow.k8s.io/command-help), прежде чем начать проверять PR или сортировать ишью. + +## Проверка пулреквестов + +Каждую неделю утверждающий доброволец документации сортирует и просматривает [пулреквесты и заявки](#сортировка-и-классификация-ишью). Такой человек называется "PR Wrangler" на неделю. Расписание ведется с помощью [планировщика PR Wrangler](https://github.com/kubernetes/website/wiki/PR-Wranglers). Чтобы поучаствовать в этом списке, посетите еженедельную встречу SIG Docs. Даже если вас не выбрали дежурным по PR на текущую неделю, вы все равно можете проверять пулреквесты (PR), которые еще не были детально просмотрены. + +В дополнение к ротации автоматизированная система добавляет в каждый новый PR и предлагает рецензентов и утверждающих для него, основываясь на списке утверждающих и рецензентов в измененных файлах. Ожидается, что автор PR будет следовать указаниям бота, поэтому PR должен быть быстро проверить. + +Мы хотим, чтобы пулреквесты принимались и публиковались как можно быстрее. Чтобы документация оставалась точной и актуальной, каждый PR должен проверяться людьми, понимающие суть темы, а также теми, кто имеет опыт написания отличной документации. + +Рецензенты и утверждающие должны предоставить конкретную и конструктивную обратную связь, чтобы заинтересованные участники были вовлечены и помогали им улучшаться. Иногда, чтобы помочь новому участнику подготовить свой PR к слиянию, требуется больше времени, чем просто переписать его самостоятельно, но проект лучше в долгосрочной перспективе, когда у нас есть множество активных участников. + +Прежде чем приступить к проверке PR, убедитесь, что вы знакомы с [руководством по содержанию документации](/docs/contribute/style/content-guide/), [руководством по оформлению документации](/docs/contribute/style/style-guide/) и [нормы поведения](/community/code-of-conduct/). + +### Поиск пулреквестов для проверки + +Чтобы посмотреть все открытые пулреквесты, перейдите на вкладку **Pull Requests** в GitHub-репозитории. +PR можно проверять только, если он соответствует всем перечисленным ниже критериям: + +- Имеет метку `cncf-cla:yes` +- Не содержит надписи WIP в описании +- Не имеет тег с фразой `do-not-merge` +- Нет конфликтов для слияния +- Сделан в правильную ветку (обычно это `master`, за исключением, если PR не относится к невыпущенной ещё функциональности) +- Не проверялся ещё детально другим проверяющим документации (то же самое касается и остальных технических рецензентов), если только этот человек явно не обратился за вашей помощью. В частности, не рекомендуется добавлять много новых комментариев после других циклов рассмотрения PR. + +Если PR не имеет условия для проверки, можно оставить комментарий, чтобы сообщить автору о текущих проблемах и предложить помочь решить их. Если автор пулреквеста был оповещён о проблемах и не устранил их в течение нескольких недель или месяцев, то рано или поздно такой PR будет закрыт. + +Если вы новичок в проверке пулреквестов или у вас недостаточно времени и возможностей, попробуйте поискать PR с тегом `size/XS` или `size/S`. Размер пулреквеста автоматически определяется по количеству изменённых строк в PR. + +#### Рецензенты и утверждающие + +В репозитории сайта Kubernetes работа построена иначе, чем в других репозиториях Kubernetes, когда речь идет о роли рецензентов и утверждающих. Для получения дополнительной информации об обязанностях рецензентов и утверждающих см. [Участие в SIG Docs](/ru/docs/contribute/participating/). Ниже вы найдете краткий обзор. + +- Рецензент проверяет содержание пулреквеста для соблюдения технической точности. Рецензент даёт понять, что PR технически точен, оставляя комментарий с `/lgtm` к PR. + + {{< note >}}Не добавляйте `/lgtm`, если вы не уверены в технической точности документации, измененной или добавленной в PR.{{< /note >}} + +- Утверждающий проверяет содержание запроса на предмет качества и соответствия рекомендациям SIG Docs, приведенным в руководствах по содержанию и оформлению. Только люди, указанные в качестве утверждающих в файле [`OWNERS`](https://github.com/kubernetes/website/blob/master/OWNERS), могут одобрить PR. Чтобы одобрить PR, оставьте комментарий `/approve` к PR. + +PR объединяется, когда у него есть комментарий `/lgtm` от кого-либо из организации Kubernetes и комментарий `/approve` от утверждающего в группе `sig-docs-maintainers`, если он не удерживается, а автор PR подписал CLA. + +{{< note >}} + +Раздел ["Участие"](/ru/docs/contribute/participating/#утверждающие) содержит больше информации для рецензентов и утверждающих, включая конкретные обязанности для утверждающих. + +{{< /note >}} + +### Проверка PR + +1. Изучите описание PR вместе с указанными ишью и ссылками, если они есть. Кратковременные мимолетные обзоры иногда могут наносит больше вреда, чем пользы, поэтому убедитесь, что вы обладаете нужными знаниями, чтобы сделать содержательный обзор. + +2. Если кто-то другой может лучше всего проверит определенный PR, упомяните этого человека, добавив комментарий `/assign @`. Если вы обратились за технической проверкой к человеку, который не занимается документацией, но при этом вы хотите сами посмотреть PR как участник группы документации, то не стесняйтесь это делать. + +3. Перейдите на вкладку **Files changed**. Посмотрите на все изменённые строки. Удалённый текст выделен красным, а строки с ним начинаются с символа `-`. Добавленный текст отмечен зелёным фоном, а строки с ним начинаются с символа `+`. Внутри строки фактически измененный контент имеет чуть более темный зеленый фон, чем остальная часть строки. + + - В частности, если в PR есть сложное форматирование или он изменяет CSS, JavaScript или другие элементы сайта, вы можете просмотреть сайт, сгенерированный с этими изменениями в PR. Перейдите на вкладку **Conversation** и нажмите ссылку **Details** в проверке `deploy/netlify` в нижней части страницы. По умолчанию ссылка открывается в текущей вкладке браузера, поэтому чтобы потерять частичный отзыв, откройте ссылку в новой вкладке. Вернитесь на вкладку **Files changed**, чтобы продолжить проверку пулреквеста. + - Убедитесь, что PR соответствует правилам содержания и оформления; если что-то не так, укажите на этом со ссылкой на раздел в руководстве. + - Если у вас есть вопрос или вы хотите прокомментировать определённое изменение, наведите курсор мыши на строку и кликните на появившуюся сине-белую кнопку с иконкой `+`. Напишите свой комментарий и нажмите на кнопку **Start a review**. + - Если вам нужно оставить больше одного комментария, сделайте это по аналогии с предыдущим шагом. + - По соглашению, если вы видите небольшую проблему, не имеющей отношение к основному назначению PR, например, опечатку или лишний пробел, вы можете сообщить о ней, начав комментарий с `nit:`, чтобы автор знал, что это незначительная ошибка. Хотя это не означает, что автор пулреквеста может проигнорировать такие проблемы. + - Когда вы всё проверили или у вас не осталось комментариев, прокрутите в верхнюю часть страницы и нажмите на кнопку **Review changes**. Далее кликните либо на **Comment** или **Request Changes**. Напишите краткий итог вашей проверки и добавьте соответствующие [Prow-команды](https://prow.k8s.io/command-help) по одной на каждой строке в поле Review Summary. SIG Docs следует [процессу проверки кода Kubernetes](https://github.com/kubernetes/community/blob/master/contributors/guide/owners.md#the-code-review-process). Все ваши комментарии будут отправлены автору PR в виде одного уведомления. + + - Если вы считаете, что PR в хорошем состоянии, чтобы его принять, добавьте команду `/approve` в резюме вашей проверки. + - Если PR не нуждается в дополнительном техническом рассмотрении, добавьте ещё команду `/lgtm`. + - Если PR *требуется* дополнительный технический обзор, добавьте команду `/assign` и после неё укажите логин человека на GitHub, который должен сделать технический анализ. Посмотрите на поле рецензентов во вступительной (фронтальной) части вверху данного Markdown-файла, чтобы выяснить, кто может провести технический разбор пулреквеста. + - Чтобы заблокировать слияние PR, используйте команду `/hold`. Она добавит метку `do-not-merge/hold`. + - Если в PR нет конфликтов и есть метки `lgtm` и `approve` (и нет метки `hold`), то он автоматически объединиться. + - Если PR имеет метки `lgtm` и/или `approve`, и появляются новые изменения, эти метки будут автоматически удалены. + + Посмотрите [список доступных команд](https://prow.k8s.io/command-help), которые можно использовать в PR. + + - Если вы ранее выбрали нажали на **Request changes** и затем автор PR решил все указанные проблемы, вы можете обновить статус проверки либо на вкладке **Files changed**, либо в нижней части вкладки **Conversation**. Обязательно укажите команду `/approve` и при необходимости выберите технических рецензентов, чтобы можно было объединить PR. + +### Редактирование PR другого человека + +Добавление комментариев в PR — полезное дело, но могут быть случаи, когда нужно сделать коммит в пулреквест другого человека, а не просто оставить свой отзыв. + +Не поддавайтесь желанию выполнить работу за другого человека, если только он явно не попросит вас об этом или вы не захотите оживить давно заброшенный PR. Хотя это может быть быстрее в краткосрочной плане, но это лишает человека возможности внести собственный вклад. + +Используемый процесс зависит от того, нужно ли вам отредактировать файл, который уже изменен в PR, либо вам нужно отредактировать файл, который в PR не участвовал. + +Вы не можете отредактировать чужой PR, если выполняется одно из условий: + +- Если автор PR отправил свою ветку непосредственно в репозиторий [https://github.com/kubernetes/website/](https://github.com/kubernetes/website/), то только рецензент с правом отправки изменений напрямую в репозиторий может вносить изменения в PR. + Авторам следует открыть PR из ветки в своей копии репозитория. +- Если автор PR явно запретил редактирование утверждающими, вы не сможете внести изменения в его PR, пока он не изменит эту настройку. + +#### Если файл уже изменён в PR + +Этот метод использует интерфейс GitHub. Вы можете использовать командную строку, если вам комфортнее работать в ней, даже если вам нужно изменить файл, который ранее редактировался в PR. + +1. Перейдите на вкладку **Files changed**. +2. Прокрутите к блоку с файлом, который вы хотите отредактировать и нажмите на иконку с карандашом. +3. Внесите изменения, напишите сообщение коммита в соответствующем поле под текстовым редактором и нажмите **Commit changes**. + +После этого ваш коммит отправляется в ветку из PR (скорее всего, в копию репозитория автора), и теперь отображается в PR, а ваши изменения отражаются на вкладке **Files changed**. Оставьте комментарий, чтобы автор PR знал, что вы что-то сделали в PR. + +Если автор использует командную строку, а не сайт GitHub для работы с этим PR, он должен получить изменения со своей копии репозитория и перебазировать свою локальную ветку на ветку своей копии, прежде чем заниматься своим PR. + +#### Если файл ещё не был изменён в PR + +Если необходимо внести изменения в файл, который не был отредактирован в рамках конкретного PR, нужно использовать командную строку. Вам придётся по душе такой метод, если вы предпочитаете использовать терминал вместо использования сайта GitHub. + +1. Узнайте URL-адрес копии репозитория автора пулреквеста. Вы можете найти его в нижней части вкладки **Conversation**. Найдите текст **Add more commits by pushing to**. Первая ссылка после этой надписи ведет на ветку, а вторая ссылка — на саму копию репозитория. Скопируйте вторую ссылку. Запомните название ветки, пригодится впоследствии. + +2. Добавьте копию репозитория как новый удаленный репозиторий. В терминале перейдите в директорию своей копии репозитория. Придумайте имя для удаленного репозитория (например, по имени логина автора на GitHub) и добавьте его, используя следующую команду: + + ```bash + git remote add + ``` + +3. Получите информацию о добавленном удаленном репозитории. Это действие не затронет локальные файлы, а только загрузит в вашу копии репозитория информацию о другой копии (например, ветки и теги). + + ```bash + git remote fetch + ``` + +4. Перейдите в ветку, полученную с удаленного репозитория. Эта команда не получится, если у вас локально уже есть ветка с таким же именем. + + ```bash + git checkout + ``` + +5. Внесите изменения и добавьте их через `git add`, а затем зафиксируйте их. + +6. Отправьте изменения в удаленный репозиторий автора. + + ```bash + git push + ``` + +7. Откройте снова сайт GitHub и обновите страницу PR. Вы увидите ваши изменения. Добавьте комментарий для автора, чтобы он был в курсе, что вы изменили его PR. + +Если автор использует командную строку, а не интерфейс на GitHub для работы над PR, ему нужно получить новые изменения из своей копии репозитоии и перебазировать свою локальную ветку на ветку своей копии репозитории, прежде чем снова заниматься собственным PR. + +## Работа из локальной копии + +В случае изменений нескольких файлов, либо добавлением новых или перемещением старых, лучше работать из локальной копии Git-репозитория на компьютере, нежели чем использовать для этого GitHub. Следующие инструкции используют командую утилиту `git`, которая предполагается, что она уже установлена на вашем компьютере. Вы можете воспользоваться ими даже, если пользуетесь графическим Git-клиента. + +### Клонирование репозитория + +Вам нужно только один раз клонировать репозиторий на каждом компьютере, на котором вы работаете с документацией Kubernetes. + +1. Создайте копию репозитория `kubernetes/website` на GitHub. В браузере перейдите по [https://github.com/kubernetes/website](https://github.com/kubernetes/website) и нажмите на кнопку **Fork**. После нескольких секунд вы будете автоматически перенаправлены на URL-адрес вашей копии, которая будет иметь следующий вид: `https://github.com//website`. + +2. В окне термина используйте команду `git clone` для получения копии репозитория. + + ```bash + git clone git@github.com//website + ``` + + После выполнения этой команды в текущей рабочей директории появится новая директория `website` с содержимым вашего репозитория на GitHub. В данном случае удаленный репозиторий `origin` будет ссылаться на вашу копию репозитория. + +3. Перейдите в новую директорию `website`. Добавьте новый удалённый репозиторий `kubernetes/website` под именем `upstream`. + + ```bash + cd website + + git remote add upstream https://github.com/kubernetes/website.git + ``` + +4. Проверьте ваши репозитории `origin` и `upstream`. + + ```bash + git remote -v + ``` + + Output is similar to: + + ```bash + origin git@github.com:/website.git (fetch) + origin git@github.com:/website.git (push) + upstream https://github.com/kubernetes/website (fetch) + upstream https://github.com/kubernetes/website (push) + ``` + +### Работа в локальном репозитории + +Прежде чем начать работать в локальном репозитории, вам нужно выяснить, из какой ветки будет основываться ваша работа. Ответ на этот вопрос зависит от того, что хотите сделать, но можно руководствоваться следующими правилами: + +- Для общих улучшений существующего контента создайте собственную ветку от ветки `master`. +- Для добавления нового контента про функциональность, которая уже есть в текущих версиях Kubernetes, начните с ветки `master`. +- В случае большой и длительной работы, над которой будут трудиться несколько участников SIG Docs, например, реорганизация контента, создайте отдельную ветку, специально предназначенной для этого. +- Для нового контента про будущие, но ещё не выпущенные версии Kubernetes, работайте в ветке предварительного выпуска, созданной специально для этой версии Kubernetes. + +Для получения дополнительной информации обратитесь к разделу [Выбор правильной ветки](/ru/docs/contribute/start/#выбор-правильной-ветки-в-git). + +После того, как вы определили, с какой ветви начать свою работу (или на какой ветке будет _базироваться_ ваша работа, если говорить в терминологии Git), следуйте определённому ниже рабочему процессу, чтобы ваша работа оставалась актуальной. + +1. Когда вы работаете локально, есть три разные копии репозитория: `local`, `upstream` и `origin`. Получите данные по удалённым репозиториям `origin` и `upstream`. Эта команда очистит кеш удаленных репозиториях без фактического изменения каких-либо из копии. + + ```bash + git fetch origin + git fetch upstream + ``` + + Этот рабочий процесс отличается от того, который определен в [сообществе GitHub](https://github.com/kubernetes/community/blob/master/contributors/guide/github-workflow.md). Здесь вам не нужно объединять вашу локальную копию `master` из репозитория `upstream/master`, прежде чем отправлять изменения в вашу копию. Этот шаг не требуется в `kubernetes/website`, потому что ваша ветка базируется на репозитории upstream. + +2. Создайте локальную рабочую ветку из наиболее подходящей ветки upstream-репозитория: `upstream/dev-1.xx` для разработчиков в конкретных версиях или `upstream/master` для всех остальных участников. В этом примере предполагается, что вы будете работать с ветки `upstream/master`. Так как ваша локальная ветка `master` не настроена для отслеживания изменений с `upstream/master` на предыдущем шаге, поэтому вам нужно явно создать свою ветку от `upstream/master`. + + ```bash + git checkout -b upstream/master + ``` + +3. После переключения на новую ветку можно начать в ней работать в текстовом редакторе. Используйте команду `git status` , чтобы посмотреть измененные файлы. + +4. Когда вы закончите работу, зафиксируйте изменения. Сначала выполните команду `git status`, чтобы увидеть, какие изменения будут добавлены в коммит. В выводе этой команды есть две важные секции: `Changes staged for commit` и `Changes not staged for commit`. Файлы в последней секции, рядом с которыми есть надпись `modified` или `untracked`, необходимо добавить, если вы хотите, чтобы они попали в коммит. Для каждого файла, который нужно добавить, используйте команду `git add`. + + ```bash + git add example-file.md + ``` + + Когда все изменённые файлы добавлены, зафиксируйте их с помощью команды `git commit`: + + ```bash + git commit -m "Your commit message" + ``` + + {{< note >}} + В сообщении коммита не указывайте идентификатор или URL-адрес ишью или пулреквеста на GitHub. Если вы это сделаете, на странице ишью или пулреквеста будет показана информация о коммите всякий раз, когда коммит будет появляться в новой Git-ветке. Вы можете сослаться на ишью и пулреквесты позже на сайте GitHub. + {{< /note >}} + +5. При желании вы можете посмотреть, как ваши изменения будут выглядеть на сайте, если запустите сайт на вашей машине с помощью команды `hugo`. Посмотрите раздел [Просмотр ваших изменений локально](#просмотр-изменений-локально). Кроме этого, вы увидите свои изменения после создания пулреквеста. + +6. Перед тем, как открывать пулреквест с вашими изменениями вам для начала отправить в ветку удаленного репозитория, чем в данном случае является `origin`. + + ```bash + git push origin + ``` + + Технически вы можете не указать имя ветки в команде `push`, но корректное выполнение команды в таком случае зависит от используемой версии Git. Результаты будут более ожидаемыми, если вы напишите название ветки. + +7. Перейдите по адресу https://github.com/kubernetes/website в вашем браузере. GitHub определит и укажет вам, что вы загрузили новую ветку в свою копию, и поэтому предложит создать пулреквест. Заполните шаблон запроса. + + - Название должно быть не длиннее 50 символов и отражать краткий итог изменений. + - Подробное описание должно содержать больше информации про исправление, включая строку типа `Fixes #12345`, если пулреквест решает проблему на GitHub. Это приведет к автоматическому закрытию указанной ишью после принятия пулреквеста. + - Вы можете добавить метки или другие метаданные и назначить рецензентов. Смотрите страницу [Сортировка и классификация ишью](#сортировка-и-классификация-ишью). + + Нажмите на кнопку **Create pull request**. + +8. Начнут выполняться автоматические тесты в зависимости от состояния сайта с вашими изменениями. Если какой-либо из тестов завершился неудачно, нажмите на ссылку **Details** для получения дополнительной информации. Если тест Netlify прошёл успешно, по ссылке **Details** вы можете найти предварительную версию сайта Kubernetes с внесенными вашими изменениями. Именно на ней рецензенты будут проверять ваши изменения. + +9. Если вам необходимо что-то дополнить, изменить пулреквест в соответствии с выполненной проверкой, либо изменить текст коммита, вы можете использовать команду ниже. + + ```bash + git commit -a --amend + ``` + + - `-a`: зафиксировать все изменения + - `--amend`: изменить предыдущий коммит вместо создания нового + + Откроется текстовый редактор, чтобы вы могли отредактировать сообщение коммита, если это нужно. + + Если вы используете `git commit -m`, как в шаге 4, вы сделаете новый коммит, а не измените исходный (предыдущий) коммит. Создание нового коммита означает, что вам нужно объединить свои коммиты до того, прежде чем пулреквест может быть объединен. + + Следуйте инструкциям в шаге 6, чтобы отправить новый коммит в удаленный репозиторий. После этого новое изменение отобразится в пулреквесте, а дальше снова запустятся тесты, а также произойдет новая сборка предварительной версии сайта на Netlify с последними изменениями. + +10. Если рецензент изменяет файлы в вашем пулреквесте, вам нужно получить новые изменения в вашей локальной копии, до того как снова начать что-то делать. Используйте команды ниже, чтобы обновить свою ветку (предполагается, что ветка уже получена с вашей копии репозитория). + + ```bash + git fetch origin + git rebase origin/ + ``` + + После перебазирования вам нужно добавить флаг `--force-with-lease`, чтобы принудительно отправить новые изменения в ветке на вашу копию. + + ```bash + git push --force-with-lease origin + ``` + +11. Может возникнуть конфликт, если кто-то, как и вы, изменил те же части файла в ветке, из которой была создана ваша ветка. Если пулреквест показывает, что есть конфликты, которые нужно разрешить, вы можете сделать это либо на сайте GitHub, либо исправить их локально. + + Сначала выполните шаг 10, чтобы актуализировать локальную ветку в соответствии с веткой в удаленном репозитории. + + Затем обновите репозиторий `upstream` и перебазируйте вашу ветку на ту, с которой она была создана, в данном случае это `upstream/master`. + + ```bash + git fetch upstream + git rebase upstream/master + ``` + + Если есть конфликты, которые Git не может разрешить автоматически, вы можете увидеть конфликтующие файлы с помощью команды `git status`. Отредактируйте каждый конфликтующий файл: найдите в них маркеры конфликта `>>>`, `<<<` и `===`. Разрешение конфликта происходит путём удаления указанных маркеров конфликта. После это нужно добавить измененные файлы с помощью команды `git add ` и продолжить перебазирование ветки, используя команду `git rebase --continue`. Когда всё зафиксировано в репозитории и не осталось неразрешенных конфликтов, команда `git status` покажет, что вы вышли из состояния перебазирования ветки и нет изменений для фиксации. На этом этапе вам осталось принудительно отправить ветку в свою копию репозитория, после чего на странице пулреквеста не должны быть конфликты. + +12. Если у вашего PR отображаются несколько сделанных коммитов после редактирования предыдущих коммитов, вам следует объединить эти несколько коммитов в один коммит, чтобы PR мог быть объединен. Проверить количество коммитов можно на вкладке `Commits` на странице PR или выполнив `git log` в терминале. Объединение коммитов (Squashing commits) — это одна из форм перебазирования. + + ```bash + git rebase -i HEAD~ + ``` + + Ключ `-i` сообщает git, что вы хотите сделать перебазирование в интерактивном режиме. В этом режиме вы сможете выбрать для git, какие коммиты нужно объединить в один. Например, в вашей ветке есть 3 коммита: + + ``` + 12345 commit 4 (2 minutes ago) + 6789d commit 3 (30 minutes ago) + 456df commit 2 (1 day ago) + ``` + + Вам нужно объединить свои последние три коммита в один-единственный. + + ``` + git rebase -i HEAD~3 + ``` + + Эта команда откроет редактор с таким содержимым: + + ``` + pick 456df commit 2 + pick 6789d commit 3 + pick 12345 commit 4 + ``` + + Измените `pick` на `squash` у тех коммитов, которые вы хотите объединить, и проверьте, что коммит с выбранным `pick` находится сверху. + + ``` + pick 456df commit 2 + squash 6789d commit 3 + squash 12345 commit 4 + ``` + + Сохраните и закройте редактор. Затем отправьте объединённый коммит в репозитории с помощью команды `git push --force-with-lease origin `. + +Если у вас возникли проблемы с разрешением конфликтов или вы долго не можете что-то разрешить, что связано с вашим пулреквестом, обратитесь за помощью в Slack-канал `#sig-docs` или в [список рассылки kubernetes-sig-docs](https://groups.google.com/forum/#!forum/kubernetes-sig-docs). + +### Просмотр изменений локально + +{{< tabs name="tab_with_hugo" >}} +{{% tab name="Hugo в контейнере" %}} + +Если вы ещё не готовы создать пулреквесты, но при этом хотите посмотреть, как будет выглядеть сайт с вашими изменениями, то можете собрать и запустить образ Docker, чтобы сгенерировать всю документацию и открыть ее на своем компьютере. + +1. Соберите образ локально: + + ```bash + make docker-image + ``` + +2. После того. как образ `kubernetes-hugo` собран, вы можете использовать его для запуска сайта: + + ```bash + make docker-serve + ``` + +3. В адресной строке браузера введите вставьте адрес `localhost:1313`. Hugo будет следить за изменениями файловой системы и пересобирать сайт по мере необходимости. + +4. Чтобы остановить локальный сайт Hugo, откройте снова терминал и введите `Ctrl+C` или просто закройте окно с терминалом. + +{{% /tab %}} +{{% tab name="Hugo на локальном компьютере" %}} + +1. Установите версию [Hugo](https://gohugo.io/getting-started/installing/), которая указана в файле [`website/netlify.toml`](https://raw.githubusercontent.com/kubernetes/website/master/netlify.toml). + +2. В терминале перейдите в корневую директорию вашей копии документации Kubernetes и введите следующую команду: + + ```bash + hugo server + ``` + +3. В адресной строке браузера скопируйте `localhost:1313`. + +4. Чтобы остановить локальный сайт Hugo, откройте снова терминал и введите `Ctrl+C` или просто закройте окно с терминалом. +{{% /tab %}} +{{< /tabs >}} + +## Сортировка и классификация ишью + +Люди в SIG Docs отвечают только за сортировку и классификацию ишью, связанных с документацией. Вопросы и проблемы общего характера также хранятся в репозитории `kubernetes/website`. + +Что вы делаете, когда сортируете ишью: + +- Проверить ишью + - Убедитесь, что ишью связана с документацией сайта. Некоторые заявки можно быстро закрыть, ответив на вопрос или указав автору на ресурс. Подробности смотрите в разделе [Заявки с помощью или отчёты об ошибке в коде](#заявки-с-помощью-или-отчёты-об-ошибке-в-коде). + - Рассмотрите, насколько обоснованной является заявка. Добавьте метку `triage/needs-information`, если в ишью описано мало подробностей, чтобы ее можно было начать решать, либо если шаблон был неправильно заполнен. + Закройте заявку, если она имеет метки `lifecycle/stale` и `triage/needs-information`. +- Добавьте метку с приоритетом (см. [руководство по сортировке заявок](https://github.com/kubernetes/community/blob/master/contributors/guide/issue-triage.md#define-priority), где подробно определены метки) + - `priority/critical-urgent` - заниматься нужно прямо сейчас + - `priority/important-soon` - нужно выполнить в течение 3 months + - `priority/important-longterm` - нужно сделать в течение 6 months + - `priority/backlog` - решение можно быть отложено на неопределенный срок indefinitely; самый низкий приоритет; делать, когда будут свободны ресурсы + - `priority/awaiting-more-evidence` - указание, что это возможно хорошая задача, которую нужно иметь на виду +- Дополнительно вы можете добавить метку `help` или `good first issue`, если определенная заявка может быть решена человеком, мало знакомым с Kubernetes или SIG Docs. В качестве руководства обратитесь к файлу [Help Wanted and Good First Issue Labels](https://github.com/kubernetes/community/blob/master/contributors/guide/help-wanted.md). +- При желании примите сами участие в ишью и отправьте PR для ее решения (в частности если она может быстро разрешена или вы ранее выполняли нечто подобное). + +С помощью [этого фильтра](https://github.com/kubernetes/website/issues?q=is%3Aissue+is%3Aopen+-label%3Apriority%2Fbacklog+-label%3Apriority%2Fimportant-longterm+-label%3Apriority%2Fimportant-soon+-label%3Atriage%2Fneeds-information+-label%3Atriage%2Fsupport+sort%3Acreated-asc) можно найти заявки, которые необходимо отсортировать. + +Если у вас есть вопросы о про сортировку, спросите в Slack-канале `#sig-docs` или в [списке рассылки kubernetes-sig-docs](https://groups.google.com/forum/#!forum/kubernetes-sig-docs). + +### Добавление и удаление меток + +Для добавления метки нужен комментарий, содержащий что-то вроде `/` или `/ `. Метка уже должна быть создана в репозитории. Если вы попытаетесь добавить несуществующую метку, команда проигнорируется. + +Примеры: + +- `/triage needs-information` +- `/priority important-soon` +- `/language ja` +- `/help` +- `/good-first-issue` +- `/lifecycle frozen` + +Для удаления метки нужен комментарий с `/remove-` или `/remove- `. + +Примеры: + +- `/remove-triage needs-information` +- `/remove-priority important-soon` +- `/remove-language ja` +- `/remove-help` +- `/remove-good-first-issue` +- `/remove-lifecycle frozen` + +Список всех меток, используемых в Kubernetes, находится [здесь](https://github.com/kubernetes/kubernetes/labels). Не все метки используются группой SIG Docs. + +### Дополнительные сведения о метках + +- Ишью может иметь несколько ярлыков. +- Некоторые метки в своём имени содержат слеш для группировки, это своего рода "подметки". Например, существует множество меток `sig/`, например, `sig/cli` и `sig/api-machinery` ([полный список](https://github.com/kubernetes/website/labels?utf8=%E2%9C%93&q=sig%2F)). +- Некоторые метки добавляются автоматически, в зависимости от метаданных файлов из ишью, либо от используемых в комментариях команд со слешем, а также от указанной информации в описании. +- Новые метки могут добавляться вручную человеком, который сортировкой ишью (либо тем, кто создает ишью). + - `kind/bug`, `kind/feature` и `kind/documentation`: баг (bug) — это проблема в текущем контенте или в функциональности, а возможность (feature) — запрос на добавление нового контента или функциональности. + Метка `kind/documentation` используется редко. + - Метки `language/ja`, `language/ko` и похожие [языковые метки](https://github.com/kubernetes/website/labels?utf8=%E2%9C%93&q=language) добавляются, если ишью относится к локализованному контенту. + +### Жизненный цикл ишью + +Ишью обычно открываются и закрываются в течение относительно короткого промежутка времени. Однако иногда решение заявки после ее создания может и не быть. Иногда ишью может оставаться открытой гораздо дольше, чем 90 дней. + +`lifecycle/stale`: после 90 дней бездействия ишью автоматически помечается как устаревшая (stale). Такая заявка будет автоматически закрыта, если эта метка не будет удалена с помощью команды `/remove-lifecycle stale`. + +`lifecycle/frozen`: заявка с данной меткой не будет считаться устаревшей после 90 дней отсутствия активности. Пользователь вручную добавляет эту метку к заявкам, которые должны оставаться открытыми значительно дольше 90 дней, например, у ишью с меткой `priority/important-longterm`. + +### Обработка специальных типов ишью + +Мы встречаем перечисленные ниже типы заявкой достаточно часто, поэтому расписали, как их обрабатывать. + +#### Дублирование заявок + +Если для какой-нибудь проблемы есть одна или несколько открытых заявок, решение этой проблемы должно быть вынесено в одну заявку. Вам нужно решить, какую заявку оставить открытой (либо вовсе открыть новую ишью), перенести всю соответствующую информацию и указать связанные заявки. Затем для всех остальных похожих заявок добавьте метку с `triage/duplicate` и закройте их. Наличие только одной-единственной заявки поможет уменьшить путаницу и избежать дублирования работы над одной и той же проблемой. + +#### Заявки про неработающие ссылки + +В зависимости от того, где сообщается о неработающей ссылке, для решения этой проблемы требуются различные действия. Неработающие ссылки в API и документации Kubectl — это заявки, связанные с автоматизацией и поэтому их нужно отмечать меткой `/priority critical-urgent`, пока проблема не будет полностью проанализирована. Все остальные неработающие ссылки — это ишью, которым нужно заниматься вручную, поэтому им нужно добавить метку `/priority important-longterm`. + +#### Заявки, связанные с блогом + +Записи в [блоге Kubernetes](https://kubernetes.io/blog/) будут терять актуальность со временем, поэтому мы поддерживаем записи, опубликованные в течение года. Если заявка сообщает о проблеме в записи блога, которой более одного года, ее следует закрыть без какого-либо исправления. + +#### Заявки с помощью или отчёты об ошибке в коде + +Некоторые открытые заявки — это проблемы с основным кодом или просьбы с помощью, когда что-то (например, учебное руководство) не работает. Для заявок, не имеющих отношение к документации, закройте её, проставив метку `triage/support` и добавив комментарий с ресурсами, где можно найти помощь (Slack, Stack Overflow) и при необходимости укажите, где нужно открыть заявку, чтобы сообщить об ошибке в функциональности (вероятно, репозиторий kubernetes/kubernetes отлично подойдет для этого). + +Пример ответа на запрос о помощи: + +```none +This issue sounds more like a request for support and less +like an issue specifically for docs. I encourage you to bring +your question to the `#kubernetes-users` channel in +[Kubernetes slack](http://slack.k8s.io/). You can also search +resources like +[Stack Overflow](http://stackoverflow.com/questions/tagged/kubernetes) +for answers to similar questions. + +You can also open issues for Kubernetes functionality in + https://github.com/kubernetes/kubernetes. + +If this is a documentation issue, please re-open this issue. +``` + +Пример ответа на сообщение об ошибке в коде: + +```none +This sounds more like an issue with the code than an issue with +the documentation. Please open an issue at +https://github.com/kubernetes/kubernetes/issues. + +If this is a documentation issue, please re-open this issue. +``` + +## Добавление документации для новой функциональности + +Каждый мажорный выпуск Kubernetes несет в себе новую функциональность, для большей части из которой нужно написать хоть краткую документацию, чтобы показать людям, как её использовать. + +Зачастую SIG-группа, ответственная за новую функциональность, представляют черновик документацию в виде пулреквеста в соответствующую ветку выпуска в репозитории `kubernetes/website`, а кто-то из команды SIG Docs могут сделать вычитку или отредактировать черновик напрямую. + +### Поиск информации о новой функциональности + +Чтобы узнать о будущей функциональности, посетите еженедельную встречу sig-release (см. страницу [Сообщество](https://kubernetes.io/community/), чтобы быть в курсе предстоящих собраний) и отслеживайте документацию к новому релизу в репозитории [kubernetes/sig-release](https://github.com/kubernetes/sig-release/). Каждый выпуск имеет поддиректорию в директории [/sig-release/tree/master/releases/](https://github.com/kubernetes/sig-release/tree/master/releases). Каждая директорию содержит график выхода новой версии, черновик с примечаниями к выпуску, а также документ, в котором перечислена команда, занимающаяся новым выпуском. + +- График выпуска содержит ссылки на все другие документы, встречи, протоколы собраний и этапы, связанные с выпуском. Он также содержит информацию о целях и сроках выпуска, а также о любых специальных процессах, используемых этом выпуске. В нижней части документа определены несколько терминов, связанных с выпуском. + + Этот документ также содержит ссылку на **лист отслеживания функциональности** — это "официальный" способ узнать про новую функциональность, запланированной в выпуске. + +- В документе команды выпуска указано, кто какую роль занимает. Если непонятно, с кем можно поговорить об определенной функциональности или вы хотите что-то спросить, то либо посетите встречу по этому выпуску, чтобы задать свой вопрос, либо обратитесь к руководителю. + +- Черновик примечаний к выпуску — хорошая отправная точка, где можно узнать чуть больше о конкретной функциональности, изменениях, устаревших возможностях и в целом что-то ещё о выпуске. Содержимое может обновляться до конца цикла выпуска, поэтому будьте начеку. + +#### Лист отслеживания функциональности + +В списке отслеживания функциональности [для данного выпуска Kubernetes](https://github.com/kubernetes/sig-release/tree/master/releases) перечислена вся функциональность, запланированная для выпуска. Каждая строка содержит название возможности, ссылку на основную заявку GitHub, уровень стабильности (Alpha, Beta или Stable), группу SIG и ответственного лица за её реализацию, информацию про документацию, черновик примечания для выпуска, а также указание, была ли функциональность уже принята. Имейте в виду следующее: + +- Функциональность в состоянии Beta и Stable обычно имеет более высокий приоритет по сравнению с версией Alpha. +- Трудно протестировать (и, следовательно, написать документацию) функциональности, которая не ещё принята или,по крайней мере, считается полнофункциональной в своем PR. +- Определение, нужна ли документировать функциональности, производится вручную, и даже если у функциональности нет метки, что ей нужна документация, это не означает, это действительно так. + +### Документирование функциональности + +Как отмечалось выше, черновик документации для новой функциональности обычно предлагается SIG-группой, ответственной за реализацию новой функциональности. Это означает, вы в данном случае будете больше наблюдающим (куратором) в данной функциональности, нежели чем полноценным автором документации для неё. + +После того, как вы выбрали функциональность для документирования/наблюдения, заявите об этом в Slack-канале `#sig-docs`, на еженедельной встрече sig-docs или напрямую в PR, отправленном SIG. Если вам дали добро, вы можете редактировать PR, используя один из способов, указанных в разделе [Редактирование PR другого человека](#редактирование-PR-другого-человека). + +Если вам нужно написать новую тему, полезны следующие ссылки: + +- [Написание новых тем](/docs/contribute/style/write-new-topic/) +- [Использование шаблонов страниц](/docs/contribute/style/page-templates/) +- [Руководство по оформлению документации](/docs/contribute/style/style-guide/) +- [Руководство по содержанию документации](/docs/contribute/style/content-guide/) + +### Члены SIG, участвующие в документировании новой функциональности + +Если вы участник SIG-группы, кто разрабатывает новую функциональность для Kubernetes, вам нужно работать с документацией SIG, чтобы убедиться, что на момент новой версии написана документация для этой функциональности. Проверьте [электронную таблицу с отслеживанием функциональности](https://github.com/kubernetes/sig-release/tree/master/releases) или присоединитесь в Slack-канал #sig-release, чтобы узнать информацию о сроках выхода. Некоторые крайние сроки касательно документации: + +- **Docs deadline - Open placeholder PRs**: откройте пулреквест в ветку `release-X.Y` в репозитории `kubernetes/website` с небольшим коммитом, который вы позже измените. Используйте команду Prow `/milestone X.Y`, чтобы назначить PR соответствующему этапу. Это уведомляет человека, который занимается документацией и ответственный за этот выпуск, что выходит документация для новой функциональности. Если функциональность не нуждается в каких-либо изменениях документации, убедитесь, что команда sig-release знает об этом, написав им сообщение в Slack-канале #sig-release. Если для функциональности нужна документация, но PR для этого ещё не создан, функциональность может быть удалена из этапа. +- **Docs deadline - PRs ready for review**: теперь ваш PR должен содержать первый черновик документации для вашей функциональности. Не беспокойтесь о форматировании или всяких улучшениях. Просто опишите, что делает эта функциональность и как ее использовать. Участник из группы документации, управляющий выпуском новой версии, будет работать вместе с вами, чтобы подготовить контент для публикации. Если вашей функциональности нужна документация и первого черновика с документацией до сих пор нет, эта функциональность может быть удалена из этапа. +- **Docs complete - All PRs reviewed and ready to merge**: если ваш PR еще не был объединен в ветку `release-X.Y` к заданному крайнему сроку, обратитесь за помощью к человеку, ответственному за выпуск новой версии. Если вашей функциональности требуется документация, но она ещё не сделана, функциональность может быть удалена из этапа. + +Если ваша функциональность находится в альфа-версии и ее не нельзя отключить, убедитесь, что вы добавили ее к [переключателем возможностей](/docs/reference/command-line-tools-reference/feature-gates/) в вашем пулреквесте. Если ваша функциональность переходит из альфа-версии, обязательно удалите ее из этого файла. + +## Участие к других репозиториях + +В [проекте Kubernetes](https://github.com/kubernetes) более 50 самостоятельных репозиториев. Многие из этих репозиториев хранят код или контент, который можно рассматривать как документацию, например, справочный текст для пользователях, сообщения об ошибках, пользовательский текст в справочниках API или даже комментарии кода. + +Если вы видите текст и не знаете, откуда он берётся, вы можете использовать поиск GitHub по репозиториям организации Kubernetes, чтобы выяснить, где встречается этот текст. Это поможет вам определиться с тем, куда создать заявку или PR. + +У каждого репозитория могут быть определены собственные процессы и правила. До того как открыть проблему или отправить PR, изучите файлы `README.md`, `CONTRIBUTING.md` и `code-of-conduct.md` в репозитории, если они есть. + +Большинство репозиториев используют шаблоны для заявок и PR. Просмотрите некоторые открытые заявки и PR, чтобы понять, как устроена работа. Обязательно как можно более подробно заполните шаблоны при открытии заявок или PR. + +## Локализация контента + +Английский является основным языком документации Kubernetes, однако мы хотим, чтобы у людей была возможность читать документацию на своём родном языке. Если вам комфортно писать на другом языке, особенно в теме программного обеспечения, вы можете помочь перевести документацию Kubernetes или помочь с существующим переводом. Посмотрите страницу [Локализация](/ru/docs/contribute/localization/) и задайте вопрос в [списке рассылки kubernetes-sig-docs](https://groups.google.com/forum/#!forum/kubernetes-sig-docs) или в канале `#sig-docs` на Slack, если вы хотите помочь. + +### Работа с локализованным контентом + +Старайтесь соблюдать эти рекомендации по работе с переведенным контентом: + +- В PR должны быть изменения касающиеся только одного языка. + + В каждом языке есть собственные рецензенты и утверждающие. + +- Рецензентам: убедитесь, что PR содержат изменения только на одном языке. + + Если PR изменяет файлы на нескольких языках, попросите автора открыть отдельные PR для каждого языка. + +{{% /capture %}} + +{{% capture whatsnext %}} + +Если вы хорошо осознали все задачи, затронутые в этом разделе, и хотите более тесно работать с командой документации Kubernetes, переходите к изучению [продвинутого руководства участника](/ru/docs/contribute/advanced/). + +{{% /capture %}}