From bd9b561ad1cc416e2440921bde2e73817260c29c Mon Sep 17 00:00:00 2001 From: Phillip Wittrock Date: Sun, 22 Jan 2017 11:48:07 -0800 Subject: [PATCH] Concept docs for kubectl configuration management methods. --- _data/concepts.yml | 3 + .../kubectl/object-management-overview.md | 21 +- ...ect-management-using-declarative-config.md | 958 ++++++++++++++++++ ...ct-management-using-imperative-commands.md | 159 +++ ...ject-management-using-imperative-config.md | 129 +++ .../tools/kubectl/simple_deployment.yaml | 16 + .../tools/kubectl/update_deployment.yaml | 15 + 7 files changed, 1283 insertions(+), 18 deletions(-) create mode 100644 docs/concepts/tools/kubectl/object-management-using-declarative-config.md create mode 100644 docs/concepts/tools/kubectl/object-management-using-imperative-commands.md create mode 100644 docs/concepts/tools/kubectl/object-management-using-imperative-config.md create mode 100644 docs/concepts/tools/kubectl/simple_deployment.yaml create mode 100644 docs/concepts/tools/kubectl/update_deployment.yaml diff --git a/_data/concepts.yml b/_data/concepts.yml index 71c6512909..7c0d0082a7 100644 --- a/_data/concepts.yml +++ b/_data/concepts.yml @@ -5,6 +5,9 @@ toc: - title: Kubectl Command Line section: - docs/concepts/tools/kubectl/object-management-overview.md + - docs/concepts/tools/kubectl/object-management-using-imperative-commands.md + - docs/concepts/tools/kubectl/object-management-using-imperative-config.md + - docs/concepts/tools/kubectl/object-management-using-declarative-config.md - title: Kubernetes Objects section: - docs/concepts/abstractions/overview.md diff --git a/docs/concepts/tools/kubectl/object-management-overview.md b/docs/concepts/tools/kubectl/object-management-overview.md index 0969086ff9..2604a50468 100644 --- a/docs/concepts/tools/kubectl/object-management-overview.md +++ b/docs/concepts/tools/kubectl/object-management-overview.md @@ -59,12 +59,6 @@ Disadvantages compared to object configuration: - Commands do not provide a source of records except for what is live. - Commands do not provide a template for creating new objects. -{% comment %} -If we use Markdown comments instead of HTML comments, they won't appear in the built HTML files. -For a tutorial on how to use Imperative Commands for app management, see: -[App Management Using Comands](/docs/tutorials/kubectl/app-management-using-commands/) -{% endcomment %} - ## Imperative object configuration When using imperative object configuration, a user operates on object @@ -124,11 +118,6 @@ Disadvantages compared to declarative object configuration: - Imperative object configuration works best on files, not directories. - Updates to live objects must be reflected in configuration files, or they will be lost during the next replacement. -{% comment %} -For a tutorial on how to use Yaml Config for app management, see: -[App Management Yaml Config](/docs/tutorials/kubectl/app-management-using-yaml-config/) -{% endcomment %} - ## Declarative object configuration When using declarative object configuration, a user operates on object @@ -170,20 +159,16 @@ Disadvantages compared to imperative object configuration: - Declarative object configuration is harder to debug and understand results when they are unexpected. - Partial updates using diffs create complex merge and patch operations. -{% comment %} -For a tutorial on how to use Yaml Config with multiple writers, see: -[App Management Yaml Config](/docs/tutorials/kubectl/app-management-using-yaml-config-multiple-writers/) -{% endcomment %} - {% endcapture %} {% capture whatsnext %} +- [Managing Kubernetes Objects Using Imperative Commands](/docs/concepts/tools/kubectl/object-management-using-imperative-commands/) +- [Managing Kubernetes Objects Using Object Configuration (Imperative)](/docs/concepts/tools/kubectl/object-management-using-imperative-config/) +- [Managing Kubernetes Objects Using Object Configuration (Declarative)](/docs/concepts/tools/kubectl/object-management-using-declarative-config/) - [Kubectl Command Reference](/docs/user-guide/kubectl/v1.5/) - [Kubernetes Object Schema Reference](/docs/resources-reference/v1.5/) {% comment %} -- [App Management Using Yaml Config](/docs/tutorials/kubectl/declarative-app-management-using-yaml-config/) -- [App Management Using Yaml Config With Multiple Writers](/docs/tutorials/kubectl/declarative-app-management-using-yaml-config-multiple-writers/) {% endcomment %} {% endcapture %} diff --git a/docs/concepts/tools/kubectl/object-management-using-declarative-config.md b/docs/concepts/tools/kubectl/object-management-using-declarative-config.md new file mode 100644 index 0000000000..ce90126be8 --- /dev/null +++ b/docs/concepts/tools/kubectl/object-management-using-declarative-config.md @@ -0,0 +1,958 @@ +--- +title: Declarative Management of Kubernetes Objects Using Configuration Files +--- + +{% capture overview %} +Kubernetes objects can be created, updated, and deleted by storing multiple +object configuration files in a directory and using `kubectl apply` to +recursively create and update those objects as needed. This method +retains writes made to live objects without merging the changes +back into the object configuration files. +{% endcapture %} + +{% capture body %} + +## Trade-offs + +The `kubectl` tool supports three kinds of object management: + +* Imperative commands +* Imperative object configuration +* Declarative object configuration + +See [Kubernetes Object Management](/docs/concepts/tools/kubectl/object-management-overview/) +for a discussion of the advantages and disadvantage of each kind of object management. + +## Before you begin + +Declarative object configuration requires a firm understanding of +the Kubernetes object definitions and configuration. Read and complete +the following documents if you have not already: + +- [Managing Kubernetes Objects Using Imperative Commands](/docs/concepts/tools/kubectl/object-management-using-imperative-commands/) +- [Imperative Management of Kubernetes Objects Using Configuration Files](/docs/concepts/tools/kubectl/object-management-using-imperative-config/) + +Following are definitions for terms used in this document: + +- *object configuration file / configuration file*: A file that defines the + configuration for a Kubernetes object. This topic shows how to pass configuration + files to `kubectl apply`. Configuration files are typically stored in source control, such as Git. +- *live object configuration / live configuration*: The live configuration + values of an object, as observed by the Kubernetes cluster. These are kept in the Kubernetes + cluster storage, typically etcd. +- *declarative configuration writer / declarative writer*: A person or software component + that makes updates to a live object. The live writers refered to in this topic make changes + to object configuration files and run `kubectl apply` to write the changes. + +## How to create objects + +Use `kubectl apply` to create all objects, except those that already exist, +defined by configuration files in a specified directory: + +```shell +kubectl apply -f / +``` + +This sets the `kubectl.kubernetes.io/last-applied-configuration: '{...}'` +annotation on each object. The annotation contains the contents of the object +configuration file that was used to create the object. + +**Note**: Add the `-R` flag to recursively process directories. + +Here's an example of an object configuration file: + +{% include code.html language="yaml" file="simple_deployment.yaml" ghlink="/docs/concepts/tools/simple_deployment.yaml" %} + +Create the object using `kubectl apply`: + +```shell +kubectl apply -f http://k8s.io/docs/concepts/tools/kubectl/simple_deployment.yaml +``` + +Print the live configuration using `kubectl get`: + +```shell +kubectl get -f http://k8s.io/docs/concepts/tools/kubectl/simple_deployment.yaml -o yaml +``` + +The output shows that the `kubectl.kubernetes.io/last-applied-configuration` annotation +was written to the live configuration, and it matches the configuration file: + +```shell +kind: Deployment +metadata: + annotations: + # ... + # This is the json representation of simple_deployment.yaml + # It was written by kubectl apply when the object was created + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"extensions/v1beta1","kind":"Deployment", + "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"}, + "spec":{"minReadySeconds":5,"template":{"metadata":{"labels":{"app":"nginx"}}, + "spec":{"containers":[{"image":"nginx:1.7.9","name":"nginx", + "ports":[{"containerPort":80}]}]}}}} + # ... +spec: + # ... + minReadySeconds: 5 + template: + metadata: + # ... + labels: + app: nginx + spec: + containers: + - image: nginx:1.7.9 + # ... + name: nginx + ports: + - containerPort: 80 + # ... + # ... + # ... + # ... +``` + +## How to update objects + +You can also use `kubectl apply` to update all objects defined in a directory, even +if those objects already exist. This approach accomplishes the following: + +1. Sets fields that appear in the configuration file in the live configuration. +2. Clears fields removed from the configuration file in the live configuration. + +```shell +kubectl apply -f / +``` + +**Note**: Add the `-R` flag to recursively process directories. + +Here's an example configuration file: + +{% include code.html language="yaml" file="simple_deployment.yaml" ghlink="/docs/concepts/tools/simple_deployment.yaml" %} + +Create the object using `kubectl apply`: + +```shell +kubectl apply -f http://k8s.io/docs/concepts/tools/kubectl/simple_deployment.yaml +``` + +**Note:** For purposes of illustration, the preceding command refers to a single +configuration file instead of a directory. + +Print the live configuration using `kubectl get`: + +```shell +kubectl get -f http://k8s.io/docs/concepts/tools/kubectl/simple_deployment.yaml -o yaml +``` + +The output shows that the `kubectl.kubernetes.io/last-applied-configuration` annotation +was written to the live configuration, and it matches the configuration file: + +```shell +kind: Deployment +metadata: + annotations: + # ... + # This is the json representation of simple_deployment.yaml + # It was written by kubectl apply when the object was created + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"extensions/v1beta1","kind":"Deployment", + "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"}, + "spec":{"minReadySeconds":5,"template":{"metadata":{"labels":{"app":"nginx"}}, + "spec":{"containers":[{"image":"nginx:1.7.9","name":"nginx", + "ports":[{"containerPort":80}]}]}}}} + # ... +spec: + # ... + minReadySeconds: 5 + template: + metadata: + # ... + labels: + app: nginx + spec: + containers: + - image: nginx:1.7.9 + # ... + name: nginx + ports: + - containerPort: 80 + # ... + # ... + # ... + # ... +``` + +Directly update the `replicas` field in the live configuration by using `kubectl scale`. +This does not use `kubectl apply`: + +```shell +kubectl scale deployment/nginx-deployment --replicas 2 +``` + +Print the live configuration using `kubectl get`: + +```shell +kubectl get -f http://k8s.io/docs/concepts/tools/kubectl/simple_deployment.yaml -o yaml +``` + +The output shows that the `replicas` field has been set to 2, and the `last-applied-configuration` +annotation does not contain a `replicas` field: + +``` +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + annotations: + # ... + # note that the annotation does not contain replicas + # because it was not updated through apply + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"extensions/v1beta1","kind":"Deployment", + "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"}, + "spec":{"minReadySeconds":5,"template":{"metadata":{"labels":{"app":"nginx"}}, + "spec":{"containers":[{"image":"nginx:1.7.9","name":"nginx", + "ports":[{"containerPort":80}]}]}}}} + # ... +spec: + replicas: 2 # written by scale + # ... + minReadySeconds: 5 + template: + metadata: + # ... + labels: + app: nginx + spec: + containers: + - image: nginx:1.7.9 + # ... + name: nginx + ports: + - containerPort: 80 + # ... +``` + +Update the `simple_deployment.yaml` configuration file to change the image from +`nginx:1.7.9` to `nginx:1.11.9`, and delete the `minReadySeconds` field: + +{% include code.html language="yaml" file="update_deployment.yaml" ghlink="/docs/concepts/tools/update_deployment.yaml" %} + +Apply the changes made to the configuration file: + +```shell +kubectl apply -f http://k8s.io/docs/concepts/tools/kubectl/updated_deployment.yaml +``` + +Print the live configuration using `kubectl get`: + +``` +kubectl get -f http://k8s.io/docs/concepts/tools/kubectl/simple_deployment.yaml -o yaml +``` + +The output shows the following changes to the live configuration: + +- The `replicas` field retains the value of 2 set by `kubectl scale`. + This is possible because it is omitted from the configuration file. +- The `image` field has been updated to `nginx:1.11.9` from `nginx:1.7.9`. +- The `last-applied-configuration` annotation has been updated with the new image. +- The `minReadySeconds` field has been cleared. +- The `last-applied-configuration` annotation no longer contains the `minReadySeconds` field. + +```shell +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + annotations: + # ... + # The annotation contains the updated image to nginx 1.11.9, + # but does not contain the updated replicas to 2 + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"extensions/v1beta1","kind":"Deployment", + "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"}, + "spec":{"template":{"metadata":{"labels":{"app":"nginx"}}, + "spec":{"containers":[{"image":"nginx:1.11.9","name":"nginx", + "ports":[{"containerPort":80}]}]}}}} + # ... +spec: + replicas: 2 # Set by `kubectl scale`. Ignored by `kubectl apply`. + # minReadySeconds cleared by `kubectl apply` + # ... + template: + metadata: + # ... + labels: + app: nginx + spec: + containers: + - image: nginx:1.11.9 # Set by `kubectl apply` + # ... + name: nginx + ports: + - containerPort: 80 + # ... + # ... + # ... + # ... +``` + +**Warning**: Mixing `kubectl apply` with the imperative object configuration commands +`create` and `replace` is not supported. This is because `create` +and `replace` do not retain the `kubectl.kubernetes.io/last-applied-configuration` +that `kubectl apply` uses to compute updates. + +**Warning**: As of Kubernetes 1.5, the `kubectl edit` command is +incompatible with `kubectl apply`, and the two should not be +used together. + +## How to delete objects + +There are two approaches to delete objects managed by `kubectl apply`. + +### Recommended: `delete -f ` + +Manually deleting objects using the imperative command is the recommended +approach, as it is more explicit about what is being deleted, and less likely +to result in the user deleting something unintentionally: + +```shell +delete -f +``` + +### Alternative: `kubectl apply -f --prune -l your=label` + +Only use this if you know what you are doing. + +**Warning:** `kubectl apply --prune` is in alpha, and backwards incompatible +changes might be introduced in subsequent releases. + +**Warning**: You must be careful when using this command, so that you +do not delete objects unintentionally. + +As an alternative to `kubectl delete`, you can use `kubectl apply` to identify objects to be deleted after their +configuration files have been removed from the directory. Apply with `--prune` +queries the API server for all objects matching a set of labels, and attempts +to match the returned live object configurations against the object +configuration files. If an object matches the query, and it does not have a +configuration file in the directory, and it does not have a `last-applied-configuration` annotation, +it is deleted. + +{% comment %} +TODO(pwittrock): We need to change the behavior to prevent the user from running apply on subdirectories unintentionally. +{% endcomment %} + +```shell +kubectl apply -f --prune -l +``` + +**Important:** Apply with prune should only be run against the root directory +containing the object configuration files. Running against sub-directories +can cause objects to be unintentionally deleted if they are returned +by the label selector query specified with `-l ` and +do not appear in the subdirectory. + +## How to view an object + +You can use `kubectl get` with `-o yaml` to view the configuration of a live object: + +```shell +kubectl get -f -o yaml +``` + +## How apply calculates differences and merges changes + +**Definition:** A *patch* is an update operation that is scoped to specific +fields of an object instead of the entire object. +This enables updating only a specific set of fields on an object without +reading the object first. + +When `kubectl apply` updates the live configuration for an object, +it does so by sending a patch request to the API server. The +patch defines updates scoped to specific fields of the live object +configuration. The `kubectl apply` command calculates this patch request +using the configuration file, the live configuration, and the +`last-applied-configuration` annotation stored in the live configuration. + +### Merge patch calculation + +The `kubectl apply` command writes the contents of the configuration file to the +`kubectl.kubernetes.io/last-applied-configuration` annotation. This +is used to identify fields that have been removed from the configuration +file and need to be cleared from the live configuration. Here are the steps used +to caluculate which fields should be deleted or set: + +1. Calculate the fields to delete. Thes are the fields present in `last-applied-configuration` and missing from the configuration file. +2. Calculate the fields to add or set. These are the fields present in the configuration file whose values don't match the live configuration. + +Here's an example. Suppose this is the configuration file for a Deployment object: + +{% include code.html language="yaml" file="update_deployment.yaml" ghlink="/docs/concepts/tools/update_deployment.yaml" %} + +Also, suppose this is the live configuration for the same Deployment object: + +```shell +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + annotations: + # ... + # note that the annotation does not contain replicas + # because it was not updated through apply + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"extensions/v1beta1","kind":"Deployment", + "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"}, + "spec":{"minReadySeconds":5,"template":{"metadata":{"labels":{"app":"nginx"}}, + "spec":{"containers":[{"image":"nginx:1.7.9","name":"nginx", + "ports":[{"containerPort":80}]}]}}}} + # ... +spec: + replicas: 2 # written by scale + # ... + minReadySeconds: 5 + template: + metadata: + # ... + labels: + app: nginx + spec: + containers: + - image: nginx:1.7.9 + # ... + name: nginx + ports: + - containerPort: 80 + # ... +``` + +Here are the merge calculations that would be performed by `kubectl apply`: + +1. Calculate the fields to delete by reading values from + `last-applied-configuration` and comparing them to values in the + configuration file. In this example, `minReadySeconds` appears in the + `last-applied-configuration` annotation, but does not appear in the configuration file. + **Action:** Clear `minReadySeconds` from the live configuration. +2. Calculate the fields to set by reading values from the configuration + file and comparing them to values in the live configuration. In this example, + the value of `image` in the configuration file does not match + the value in the live configuration. **Action:** Set the value of `image` in the live configuration. +3. Set the `last-applied-configuration` annotation to match the value + of the configuration file. +4. Merge the results from 1, 2, 3 into a single patch request to the API server. + +Here is the live configuration that is the result of the merge: + +```shell +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + annotations: + # ... + # The annotation contains the updated image to nginx 1.11.9, + # but does not contain the updated replicas to 2 + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"extensions/v1beta1","kind":"Deployment", + "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"}, + "spec":{"template":{"metadata":{"labels":{"app":"nginx"}}, + "spec":{"containers":[{"image":"nginx:1.11.9","name":"nginx", + "ports":[{"containerPort":80}]}]}}}} + # ... +spec: + replicas: 2 # Set by `kubectl scale`. Ignored by `kubectl apply`. + # minReadySeconds cleared by `kubectl apply` + # ... + template: + metadata: + # ... + labels: + app: nginx + spec: + containers: + - image: nginx:1.11.9 # Set by `kubectl apply` + # ... + name: nginx + ports: + - containerPort: 80 + # ... + # ... + # ... + # ... +``` + +{% comment %} +TODO(1.6): For 1.6, add the following bullet point to 1. + +- clear fields explicitly set to null in the local object configuration file regardless of whether they appear in the last-applied-configuration +{% endcomment %} + +### How different types of fields are merged + +How a particular field in a configuration file is merged with +with the live configuration depends on the +type of the field. There are several types of fields: + +- *primitive*: A field of type string, integer, or boolean. + For example, `image` and `replicas` are primitive fields. **Action:** Replace. + +- *map*, also called *object*: A field of type map or a complex type that contains subfields. For example `labels` + and `annotations` are maps; `spec` and `metadata` are complex types. **Action:** Merge elements or subfields. + +- *list*: A field containing a list of items that can be either primitive types, maps, or complex types. + For example, `containers`, `ports`, and `args` are lists. **Action:** Varies. + +When `kubectl apply` updates a map or list field, it typically does +not replace the entire field, but instead updates the individual subelements. +For instance, when merging the `spec` on a Deployment, the entire `spec` is +not replaced. Instead the subfields of `spec`, such as `replicas`, are compared +and merged. + +### Merging changes to primitive fields + +Primative fieldss are replaced or cleared. + +**Note:** '-' is used for "not applicable" because the value is not used. + +| Field in object configuration file | Field in live object configuration | Field in last-applied-configuration | Action | +|-------------------------------------|------------------------------------|-------------------------------------|-------------------------------------------| +| Yes | Yes | - | Set live to configuration file value. | +| Yes | No | - | Set live to local configuration. | +| No | - | Yes | Clear from live configuration. | +| No | - | No | Do nothing. Keep live value. | + +### Merging changes to map or complex fields + +Fields that represent maps or complex-types are merged by comparing each of the sub fields or elements of of the map / complex-type: + +**Note:** '-' is used for "not applicable" because the value is not used. + +| Key in object configuration file | Key in live object configuration | Field in last-applied-configuration | Action | +|-------------------------------------|------------------------------------|-------------------------------------|----------------------------------| +| Yes | Yes | - | Compare sub fields values. | +| Yes | No | - | Set live to local configuration. | +| No | - | Yes | Delete from live configuration. | +| No | - | No | Do nothing. Keep live value. | + +### Merging changes for fields of type list + +Merging changes to a list uses one of three strategies: + +* Replace the list. +* Merge individual elements in a list of complex elements. +* Merge a list of primitive elements. + +The choice of strategy is made on a per-field basis. + +#### Replace the list + +Treat the list the same as a primitive field. Replace or delete the +entire list. This preserves ordering. + +**Example:** Use `kubectl apply` to update the `args` field of a Container in a Pod. This sets +the value of `args` in the live configuration to the value in the configuration file. +Any `args` elements that had previously been added to the live configuration are lost. +The order of the `args` elements defined in the configuration file is +retained in the live configuration. + +```yaml +# last-applied-configuration value + args: ["a, b"] + +# configuration file value + args: ["a", "c"] + +# live configuration + args: ["a", "b", "d"] + +# result after merge + args: ["a", "c"] +``` + +**Explanation:** The merge used the configuration file value as the new list value. + +#### Merge individual elements of a list of complex elements: + +Treat the list as a map, and treat a specific field of each element as a key. +Add, delete, or update individual elements. This does not preserve ordering. + +This merge strategy uses a special tag on each field called a `mergeKey`. The +`mergeKey` is defined for each field in the Kubernetes source code: +[types.go](https://github.com/kubernetes/kubernetes/blob/master/pkg/api/v1/types.go#L2119) +When merging a list of complex elements, the field specified as the `mergeKey` for a given element +is used like a map key for that element. + +**Example:** Use `kubectl apply` to update the `containers` field of a PodSpec. +This merges the list as though `containers` was a map where each element is keyed +by `name`. + +```yaml +# last-applied-configuration value + containers: + - name: nginx + image: nginx:1.10 + - name: nginx-helper-a # key: nginx-helper-a; will be deleted in result + image: helper:1.3 + - name: nginx-helper-b # key: nginx-helper-b; will be retained + image: helper:1.3 + +# configuration file value + containers: + - name: nginx + image: nginx:1.11 + - name: nginx-helper-b + image: helper:1.3 + - name: nginx-helper-c # key: nginx-helper-c; will be added in result + image: helper:1.3 + +# live configuration + containers: + - name: nginx + image: nginx:1.10 + - name: nginx-helper-a + image: helper:1.3 + - name: nginx-helper-b + image: helper:1.3 + args: ["run"] # Field will be retained + - name: nginx-helper-d # key: nginx-helper-d; will be retained + image: helper:1.3 + +# result after merge + containers: + - name: nginx + image: nginx:1.10 + # Element nginx-helper-a was deleted + - name: nginx-helper-b + image: helper:1.3 + args: ["run"] # Field was retained + - name: nginx-helper-c # Element was added + image: helper:1.3 + - name: nginx-helper-d # Element was ignored + image: helper:1.3 +``` + +**Explanation:** + +- The container named "nginx-helper-a" was deleted because no container + named "nginx-helper-a" appeared in the configuration file. +- The container named "nginx-helper-b" retained the changes to `args` + in the live configuration. `kubectl apply` was able to identify + that "nginx-helper-b" in the live configuration was the same + "nginx-helper-b" as in the configuration file, even though their fields + had different values (no `args` in the configuration file). This is + because the `mergeKey` field value (name) was identical in both. +- The container named "nginx-helper-c" was added because no container + with that name appeared in the live configuration, but one with + that name appeared in the configuration file. +- The container named "nginx-helper-d" was retained because + no element with that name appeared in the last-applied-configuration. + +#### Merge a list of primitive elements + +As of Kubernetes 1.5, merging lists of primitive elements is not supported. + +**Note:** Which of the above strategies is chosen for a given field is controlled by +the `patchStrategy` tag in [types.go](https://github.com/kubernetes/kubernetes/blob/master/pkg/api/v1/types.go#L2119) +If no `patchStrategy` is specified for a field of type list, then +the list is replaced. + +{% comment %} +TODO(pwittrock): Uncomment this for 1.6 + +- Treat the list as a set of primitives. Replace or delete individual + elements. Does not preserve ordering. Does not preserve duplicates. + +**Example:** Using apply to update the `finalizers` field of ObjectMeta +keeps elements added to the live configuration. Ordering of finalizers +is lost. +{% endcomment %} + +## Default field values + +The API server sets certain fields to default values in the live configuration if they are +not specified when the object is created. + +Here's a configuration file for a Deployment. The file does not specify `strategy` or `selector`: + +{% include code.html language="yaml" file="simple_deployment.yaml" ghlink="/docs/concepts/tools/simple_deployment.yaml" %} + +Create the object using `kubectl apply`: + +```shell +kubectl apply -f http://k8s.io/docs/concepts/tools/kubectl/simple_deployment.yaml +``` + +Print the live configuration using `kubectl get`: + +```shell +kubectl get -f http://k8s.io/docs/concepts/tools/kubectl/simple_deployment.yaml -o yaml +``` + +The output shows that the API server set several fields to default values in the live +configuration. These fields were not specified in the configuration file. + +```shell +apiVersion: extensions/v1beta1 +kind: Deployment +# ... +spec: + minReadySeconds: 5 + replicas: 1 # defaulted by apiserver + selector: + matchLabels: # defaulted by apiserver - derived from template.metadata.labels + app: nginx + strategy: + rollingUpdate: # defaulted by apiserver - derived from strategy.type + maxSurge: 1 + maxUnavailable: 1 + type: RollingUpdate # defaulted apiserver + template: + metadata: + creationTimestamp: null + labels: + app: nginx + spec: + containers: + - image: nginx:1.7.9 + imagePullPolicy: IfNotPresent # defaulted by apiserver + name: nginx + ports: + - containerPort: 80 + protocol: TCP # defaulted by apiserver + resources: {} # defaulted by apiserver + terminationMessagePath: /dev/termination-log # defaulted by apiserver + dnsPolicy: ClusterFirst # defaulted by apiserver + restartPolicy: Always # defaulted by apiserver + securityContext: {} # defaulted by apiserver + terminationGracePeriodSeconds: 30 # defaulted by apiserver +# ... +``` + +**Note:** Some of the fields' default values have been derived from +the values of other fields that were specified in the configuration file, +such as the `selector` field. + +In a patch request, defaulted fields are not re-defaulted unless they are explicitly cleared +as part of a patch request. This can cause unexpected behavior for +fields that are defaulted based +on the values of other fields. When the other fields are later changed, +the values defaulted from them will not be updated unless they are +explicitly cleared. + +For this reason, it is recommended that certain fields defaulted +by the server are explicitly defined in the configuration file, even +if the desired values match the server defaults. This makes it +easier to recognize conflicting values that will not be re-defaulted +by the server. + +**Example:** + +```yaml +# last-applied-configuration +spec: + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.7.9 + ports: + - containerPort: 80 + +# configuration file +spec: + strategy: + type: Recreate # updated value + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.7.9 + ports: + - containerPort: 80 + +# live configuration +spec: + strategy: + type: RollingUpdate # defaulted value + rollingUpdate: # defaulted value derived from type + maxSurge : 1 + maxUnavailable: 1 + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.7.9 + ports: + - containerPort: 80 + +# result after merge - ERROR! +spec: + strategy: + type: Recreate # updated value: incompatible with rollingUpdate + rollingUpdate: # defaulted value: incompatible with "type: Recreate" + maxSurge : 1 + maxUnavailable: 1 + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.7.9 + ports: + - containerPort: 80 +``` + +**Explanation:** + +1. The user creates a Deployment without defining `strategy.type`. +2. The server defaults `strategy.type` to `RollingUpdate` and defaults the + `strategy.rollingUpdate` values. +3. The user changes `strategy.type` to `Recreate`. The `strategy.rollingUpdate` + values remain at their defaulted values, though the server expects them to be cleared. + If the `strategy.rollingUpdate` values had been defined initially in the configuration file, + it would have been more clear that they needed to be deleted. +4. Apply fails because `strategy.rollingUpdate` is not cleared. The `strategy.rollingupdate` + field cannot be defined with a `strategy.type` of `Recreate`. + +Recommendation: These fields should be explicitly defined in the object configuration file: + +- Selectors and PodTemplate labels on workloads, such as Deployment, StatefulSet, Job, DaemonSet, + ReplicaSet, and ReplicationController +- Deployment rollout strategy + +### How to clear server-defaulted fields or fields set by other writers + +As of Kubernetes 1.5, fields that do not appear in the configuration file cannot be +cleared by a merge operation. Here are some workarounds: + +Option 1: Remove the field by directly modifying the live object. + +**Note:** As of Kubernetes 1.5, `kubectl edit` does not work with `kubectl apply`. +Using these together will cause unexpected behavior. + +Option 2: Remove the field through the configuration file. + +1. Add the field to the configuration file to match the live object. +1. Apply the configuration file; this updates the annotation to include the field. +1. Delete the field from the configuration file. +1. Apply the configuration file; this deletes the field from the live object and annotation. + +{% comment %} +TODO(1.6): Update this with the following for 1.6 + +Fields that do not appear in the configuration file can be cleared by +setting their values to `null` and then applying the configuration file. +For fields defaulted by the server, this triggers re-defaulting +the values. +{% endcomment %} + +## How to change ownership of a field between the configuration file and direct imperative writers + +These are the only methods you should use to change an individual object field: + +- Use `kubectl apply`. +- Write directly to the live configuration without modifying the configuration file: +for example, use `kubectl scale`. + +### Changing the owner from a direct imperative writer to a configuration file + +Add the field to the configuration file. For the field, discontinue direct updates to +the live configuration that do not go through `kubectl apply`. + +### Changing the owner from a configuration file to a direct imperative writer + +As of Kubernetes 1.5, changing ownership of a field from a configuration file to +an imperative writer requires manual steps: + +- Remove the field from the configuration file. +- Remove the field from the `kubectl.kubernetes.io/last-applied-configuration` annotation on the live object. + +## Changing management methods + +Kubernetes objects should be managed using only one method at a time. +Switching from one method to another is possible, but is a manual process. + +**Exception:** It is OK to use imperative deletion with declarative management. + +{% comment %} +TODO(pwittrock): We need to make using imperative commands with +declarative object configuration work so that it doesn't write the +fields to the annotation, and instead. Then add this bullet point. + +- using imperative commands with declarative configuration to manage where each manages different fields. +{% endcomment %} + +### Migrating from imperative command management to declarative object configuration + +Migrating from imperative command management to declarative object +configuration involves several manual steps: + +1. Export the live object to a local configuration file: + + kubectl get / -o yaml --export > _.yaml + +1. Manually remove the `status` field from the configuration file. + + **Note:** This step is optional, as `kubectl apply` does not update the status field + even if it is present in the configuration file. + +1. Set the `kubectl.kubernetes.io/last-applied-configuration` annotation on the object: + + kubectl replace --save-config -f _.yaml + +1. Change processes to use `kubectl apply` for managing the object exclusively. + +{% comment %} +TODO(pwittrock): Why doesn't export remove the status field? Seems like it should. +{% endcomment %} + +### Migrating from imperative object configuration to declarative object configuration + +1. Set the `kubectl.kubernetes.io/last-applied-configuration` annotation on the object: + + kubectl replace --save-config -f _.yaml + +1. Change processes to use `kubectl apply` for managing the object exclusively. + +## Defining controller selectors and PodTemplate labels + +**Warning**: Updating selectors on controllers is strongly discouraged. + +The recommended approach is to define a single, immutable PodTemplate label +used only by the controller selector with no other semantic meaning. + +**Example:** + +```yaml +selector: + matchLabels: + controller-selector: "v1beta1/deployment/nginx" +template: + metadata: + labels: + controller-selector: "v1beta1/deployment/nginx" +``` + +## Support for ThirdPartyResources + +As of Kubernetes 1.5, ThirdPartyResources are not supported by `kubectl apply`. +The recommended approach for ThirdPartyResources is to use [imperative object configuration](/docs/concepts/tools/kubectl/object-management-using-imperative-config/). +{% endcapture %} + +{% capture whatsnext %} +- [Managing Kubernetes Objects Using Imperative Commands](/docs/concepts/tools/kubectl/object-management-using-imperative-commands/) +- [Imperative Management of Kubernetes Objects Using Configuration Files](/docs/concepts/tools/kubectl/object-management-using-imperative-config/) +- [Kubectl Command Reference](/docs/user-guide/kubectl/v1.5/) +- [Kubernetes Object Schema Reference](/docs/resources-reference/v1.5/) +{% endcapture %} + +{% include templates/concept.md %} diff --git a/docs/concepts/tools/kubectl/object-management-using-imperative-commands.md b/docs/concepts/tools/kubectl/object-management-using-imperative-commands.md new file mode 100644 index 0000000000..b49114f04a --- /dev/null +++ b/docs/concepts/tools/kubectl/object-management-using-imperative-commands.md @@ -0,0 +1,159 @@ +--- +title: Managing Kubernetes Objects Using Imperative Commands +--- + +{% capture overview %} +Kubernetes objects can quickly be created, updated, and deleted directly using +imperative commands built into the `kubectl` command-line tool. This document +explains how those commands are organized and how to use them to manage live objects. +{% endcapture %} + +{% capture body %} + +## Trade-offs + +The `kubectl` tool supports three kinds of object management: + +* Imperative commands +* Imperative object configuration +* Declarative object configuration + +See [Kubernetes Object Management](/docs/concepts/tools/kubectl/object-management-overview/) +for a discussion of the advantages and disadvantage of each kind of object management. + +## How to create objects + +The `kubectl` tool supports verb-driven commands for creating some of the most common +object types. The commands are named to be recognizable to users unfamiliar with +the Kubernetes object types. + +- `run`: Create a new Deployment object to run Containers in one or more Pods. +- `expose`: Create a new Service object to load balance traffic across Pods. +- `autoscale`: Create a new Autoscaler object to automatically horizontally scale a controller, such as a Deployment. + +The `kubectl` tool also supports creation commands driven by object type. +These commands support more object types and are more explicit about +their intent, but require users to know the type of objects they intend +to create. + +- `create [] ` + +Some objects types have subtypes that you can specify in the `create` command. +For example, the Service object has several subtypes including ClusterIP, +LoadBalancer, and NodePort. Here's an example that creates a Service with +subtype NodePort: + +```shell +kubectl create service nodeport +``` + +In the preceding example, the `create service nodeport` command is called +a subcommand of the `create service` command. + +You can use the `-h` flag to find the arguments and flags supported by +a subcommand: + +```shell +kubectl create service nodeport -h +``` + +## How to update objects + +The `kubectl` command supports verb-driven commands for some common update operations. +These commands are named to enable users unfamiliar with Kubernetes +objects to perform updates without knowing the specific fields +that must be set: + +- `scale`: Horizontally scale a controller to add or remove Pods by updating the replica count of the controller. +- `annotate`: Add or remove an annotation from an object. +- `label`: Add or remove a label from an object. + +The `kubectl` command also supports update commands driven by an aspect of the object. +Setting this aspect may set different fields for different object types: + +- `set` : Set an aspect of an object. + +**Note**: In Kubernetes version 1.5, not every verb-driven command has an +associated field-driven command. + +The `kubectl` tool supports these additional ways to update a live object directly, +however they require a better understanding of the Kubernetes object schema. + +- `edit`: Directly edit the raw configuration of a live object by opening its configuration in an editor. +- `patch`: Directly modify specific fields of a live object by using a patch string. +For more details on patch strings, see the patch section in +[API Conventions](https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#patch-operations). + +## How to delete objects + +You can use the `delete` command to delete an object from a cluster: + +- `delete /` + +**Note**: You can use `kubectl delete` for both imperative commands and imperative object +configuration. The difference is in the arguments passed to the command. To use +`kubectl delete` as an imperative command, pass the object to be deleted as +an argument. Here's an example that passes a Deployment object named nginx: + +```shell +kubectl delete deployment/nginx +``` + +## How to view an object + +{% comment %} +TODO(pwittrock): Uncomment this when implemented. + +You can use `kubectl view` to print specific fields of an object. + +- `view`: Prints the value of a specific field of an object. + +{% endcomment %} + + + +There are several commands for printing information about an object: + +- `get`: Prints basic information about matching objects. Use `get -h` to see a list of options. +- `describe`: Prints aggregated detailed information about matching objects. +- `logs`: Prints the stdout and stderr for a container running in a Pod. + +## Using `set` commands to modify objects before creation + +There are some object fields that don't have a flag you can use +in a `create` command. In some of those cases, you can use a combination of +`set` and `create` to specify a value for the field before object +creation. This is done by piping the output of the `create` command to the +`set` command, and then back to the `create` command. Here's an example: + +```sh +kubectl create service clusterip -o yaml --dry-run | kubectl set selector --local -f - 'environment=qa' -o yaml | kubectl create -f - +``` + +1. The `create service -o yaml --dry-run` command creates the configuration for the Service, but prints it to stdout as YAML instead of sending it to the Kubernetes API server. +1. The `set --local -f - -o yaml` command reads the configuration from stdin, and writes the updated configuration to stdout as YAML. +1. The `kubectl create -f -` command creates the object using the configuration provided via stdin. + +## Using `--edit` to modify objects before creation + +You can use `kubectl create --edit` to make arbitrary changes to an object +before it is created. Here's an example: + +```sh +kubectl create service clusterip my-svc -o yaml --dry-run > /tmp/srv.yaml +kubectl create --edit -f /tmp/srv.yaml +``` + +1. The `create service` command creates the configuration for the Service and saves it to `/tmp/srv.yaml`. +1. The `create --edit` command opens the configuration file for editing before it creates the object. + +{% endcapture %} + +{% capture whatsnext %} +- [Managing Kubernetes Objects Using Object Configuration (Imperative)](/docs/concepts/tools/kubectl/object-management-using-imperative-config/) +- [Managing Kubernetes Objects Using Object Configuration (Declarative)](/docs/concepts/tools/kubectl/object-management-using-declarative-config/) +- [Kubectl Command Reference](/docs/user-guide/kubectl/v1.5/) +- [Kubernetes Object Schema Reference](/docs/resources-reference/v1.5/) +{% endcapture %} + +{% include templates/concept.md %} diff --git a/docs/concepts/tools/kubectl/object-management-using-imperative-config.md b/docs/concepts/tools/kubectl/object-management-using-imperative-config.md new file mode 100644 index 0000000000..2ce6319749 --- /dev/null +++ b/docs/concepts/tools/kubectl/object-management-using-imperative-config.md @@ -0,0 +1,129 @@ +--- +title: Imperative Management of Kubernetes Objects Using Configuration Files +--- + +{% capture overview %} +Kubernetes objects can be created, updated, and deleted by using the `kubectl` +command-line tool along with an object configuration file written in YAML or JSON. +This document explains how to define and manage objects using configuration files. +{% endcapture %} + +{% capture body %} + +## Trade-offs + +The `kubectl` tool supports three kinds of object management: + +* Imperative commands +* Imperative object configuration +* Declarative object configuration + +See [Kubernetes Object Management](/docs/concepts/tools/kubectl/object-management-overview/) +for a discussion of the advantages and disadvantage of each kind of object management. + +## How to create objects + +You can use `kubectl create -f` to create an object from a configuration file. +Refer to the [kubernetes object schema reference](/docs/resources-reference/v1.5/) +for details. + +- `create -f ` + +## How to update objects + +You can use `kubectl replace -f` to update a live object according to a +configuration file. + +- `replace -f ` + +## How to delete objects + +You can use `kubectl delete -f` to delete an object that is described in a +configuration file. + +- `delete -f ` + +## How to view an object + +You can use `kubectl get -f` to view information about an object that is +described in a configuration file. + +- `get -f -o yaml` + +The `-o yaml` flag specifies that the full object configuration is printed. +Use `get -h` to see a list of options. + +## Limitations + +The `create`, `replace`, and `delete` commands work well when each object's +configuration is fully defined and recorded in its configuration +file. However when a live object is updated, and the updates are not merged +into its configuration file, the updates will be lost the next time a `replace` +is executed. This is can happen if a controller, such as +a HorizontalPodAutoscaler, makes updates directly to a live object. Here's +an example: + +1. You create an object from a configuration file. +1. Another source updates the object by changing some field. +1. You replace the object from the configuration file. Changes made by +the other source in step 2 are lost. + +If you need to support multiple writers to the same object, you can use +`kubectl apply` to manage the object. + +## Creating and editing an object from a URL without saving the configuration + +Suppose you have the URL of an object configuration file. You can use +`kubectl create --edit` to make changes to the configuration before the +object is created. This is particularly useful for tutorials and tasks +that point to a configuration file that could be modified by the reader. + +```sh +kubectl create -f --edit +``` + +## Migrating from imperative commands to imperative object configuration + +Migrating from imperative commands to imperative object configuration involves +several manual steps. + +1. Export the live object to a local object configuration file: + + kubectl get / -o yaml --export > _.yaml + +1. Manually remove the status field from the object configuration file. + +1. For subsequent object management, use `replace` exclusively. + + kubectl replace -f _.yaml + + +## Defining controller selectors and PodTemplate labels + +**Warning**: Updating selectors on controllers is strongly discouraged. + +The recommended approach is to define a single, immutable PodTemplate label +used only by the controller selector with no other semantic meaning. + +Example label: + +```yaml +selector: + matchLabels: + controller-selector: "v1beta1/deployment/nginx" +template: + metadata: + labels: + controller-selector: "v1beta1/deployment/nginx" +``` + +{% endcapture %} + +{% capture whatsnext %} +- [Managing Kubernetes Objects Using Imperative Commands](/docs/concepts/tools/kubectl/object-management-using-imperative-commands/) +- [Managing Kubernetes Objects Using Object Configuration (Declarative)](/docs/concepts/tools/kubectl/object-management-using-declarative-config/) +- [Kubectl Command Reference](/docs/user-guide/kubectl/v1.5/) +- [Kubernetes Object Schema Reference](/docs/resources-reference/v1.5/) +{% endcapture %} + +{% include templates/concept.md %} diff --git a/docs/concepts/tools/kubectl/simple_deployment.yaml b/docs/concepts/tools/kubectl/simple_deployment.yaml new file mode 100644 index 0000000000..0348883c24 --- /dev/null +++ b/docs/concepts/tools/kubectl/simple_deployment.yaml @@ -0,0 +1,16 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: nginx-deployment +spec: + minReadySeconds: 5 + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.7.9 + ports: + - containerPort: 80 diff --git a/docs/concepts/tools/kubectl/update_deployment.yaml b/docs/concepts/tools/kubectl/update_deployment.yaml new file mode 100644 index 0000000000..d2c2d82010 --- /dev/null +++ b/docs/concepts/tools/kubectl/update_deployment.yaml @@ -0,0 +1,15 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: nginx-deployment +spec: + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.11.9 # update the image + ports: + - containerPort: 80