Add update to statefulset concepts and basic tutorial (#4174)
* Add update to statefulset concpets and basic tutorial * Address tech comments.
This commit is contained in:
parent
329aa4672f
commit
4641b51e1b
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
assignees:
|
assignees:
|
||||||
- bprashanth
|
|
||||||
- enisoc
|
- enisoc
|
||||||
- erictune
|
- erictune
|
||||||
- foxish
|
- foxish
|
||||||
|
@ -14,7 +13,7 @@ redirect_from:
|
||||||
---
|
---
|
||||||
|
|
||||||
{% capture overview %}
|
{% capture overview %}
|
||||||
**StatefulSets are a beta feature in 1.5. This feature replaces the
|
**StatefulSets are a beta feature in 1.7. This feature replaces the
|
||||||
PetSets feature from 1.4. Users of PetSets are referred to the 1.5
|
PetSets feature from 1.4. Users of PetSets are referred to the 1.5
|
||||||
[Upgrade Guide](/docs/tasks/manage-stateful-set/upgrade-pet-set-to-stateful-set/)
|
[Upgrade Guide](/docs/tasks/manage-stateful-set/upgrade-pet-set-to-stateful-set/)
|
||||||
for further information on how to upgrade existing PetSets to StatefulSets.**
|
for further information on how to upgrade existing PetSets to StatefulSets.**
|
||||||
|
@ -34,8 +33,9 @@ following.
|
||||||
* Stable, persistent storage.
|
* Stable, persistent storage.
|
||||||
* Ordered, graceful deployment and scaling.
|
* Ordered, graceful deployment and scaling.
|
||||||
* Ordered, graceful deletion and termination.
|
* Ordered, graceful deletion and termination.
|
||||||
|
* Ordered, automated rolling updates.
|
||||||
|
|
||||||
In the above, stable is synonymous with persistence across Pod (re)schedulings.
|
In the above, stable is synonymous with persistence across Pod (re)scheduling.
|
||||||
If an application doesn't require any stable identifiers or ordered deployment,
|
If an application doesn't require any stable identifiers or ordered deployment,
|
||||||
deletion, or scaling, you should deploy your application with a controller that
|
deletion, or scaling, you should deploy your application with a controller that
|
||||||
provides a set of stateless replicas. Controllers such as
|
provides a set of stateless replicas. Controllers such as
|
||||||
|
@ -48,7 +48,6 @@ provides a set of stateless replicas. Controllers such as
|
||||||
* The storage for a given Pod must either be provisioned by a [PersistentVolume Provisioner](http://releases.k8s.io/{{page.githubbranch}}/examples/persistent-volume-provisioning/README.md) based on the requested `storage class`, or pre-provisioned by an admin.
|
* The storage for a given Pod must either be provisioned by a [PersistentVolume Provisioner](http://releases.k8s.io/{{page.githubbranch}}/examples/persistent-volume-provisioning/README.md) based on the requested `storage class`, or pre-provisioned by an admin.
|
||||||
* Deleting and/or scaling a StatefulSet down will *not* delete the volumes associated with the StatefulSet. This is done to ensure data safety, which is generally more valuable than an automatic purge of all related StatefulSet resources.
|
* Deleting and/or scaling a StatefulSet down will *not* delete the volumes associated with the StatefulSet. This is done to ensure data safety, which is generally more valuable than an automatic purge of all related StatefulSet resources.
|
||||||
* StatefulSets currently require a [Headless Service](/docs/concepts/services-networking/service/#headless-services) to be responsible for the network identity of the Pods. You are responsible for creating this Service.
|
* StatefulSets currently require a [Headless Service](/docs/concepts/services-networking/service/#headless-services) to be responsible for the network identity of the Pods. You are responsible for creating this Service.
|
||||||
* Updating an existing StatefulSet is currently a [manual process](/docs/tutorials/stateful-application/basic-stateful-set/#updating-containers).
|
|
||||||
|
|
||||||
## Components
|
## Components
|
||||||
The example below demonstrates the components of a StatefulSet.
|
The example below demonstrates the components of a StatefulSet.
|
||||||
|
@ -59,7 +58,6 @@ The example below demonstrates the components of a StatefulSet.
|
||||||
PersistentVolume Provisioner.
|
PersistentVolume Provisioner.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
---
|
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
|
@ -154,7 +152,7 @@ PersistentVolume Claims. Note that, the PersistentVolumes associated with the
|
||||||
Pods' PersistentVolume Claims are not deleted when the Pods, or StatefulSet are deleted.
|
Pods' PersistentVolume Claims are not deleted when the Pods, or StatefulSet are deleted.
|
||||||
This must be done manually.
|
This must be done manually.
|
||||||
|
|
||||||
## Deployment and Scaling Guarantee
|
## Deployment and Scaling Guarantees
|
||||||
|
|
||||||
* For a StatefulSet with N replicas, when Pods are being deployed, they are created sequentially, in order from {0..N-1}.
|
* For a StatefulSet with N replicas, when Pods are being deployed, they are created sequentially, in order from {0..N-1}.
|
||||||
* When Pods are being deleted, they are terminated in reverse order, from {N-1..0}.
|
* When Pods are being deleted, they are terminated in reverse order, from {N-1..0}.
|
||||||
|
@ -175,5 +173,62 @@ If a user were to scale the deployed example by patching the StatefulSet such th
|
||||||
is fully shutdown and deleted. If web-0 were to fail after web-2 has been terminated and
|
is fully shutdown and deleted. If web-0 were to fail after web-2 has been terminated and
|
||||||
is completely shutdown, but prior to web-1's termination, web-1 would not be terminated
|
is completely shutdown, but prior to web-1's termination, web-1 would not be terminated
|
||||||
until web-0 is Running and Ready.
|
until web-0 is Running and Ready.
|
||||||
|
|
||||||
|
### Pod Management Policies
|
||||||
|
In Kubernetes 1.7 and later, StatefulSet allows you to relax its ordering guarantees while
|
||||||
|
preserving its uniqueness and identity guarantees via its `.spec.podManagementPolicy` field.
|
||||||
|
|
||||||
|
#### OrderedReady Pod Management
|
||||||
|
|
||||||
|
`OrderedReady` pod management is the default for StatefulSets. It implements the behavior
|
||||||
|
described [above](#deployment-and-scaling-guarantees).
|
||||||
|
|
||||||
|
#### Parallel Pod Management
|
||||||
|
|
||||||
|
`Parallel` pod management tells the StatefulSet controller to launch or
|
||||||
|
terminate all Pods in parallel, and to not wait for Pods to become Running
|
||||||
|
and Ready or completely terminated prior to launching or terminating another
|
||||||
|
Pod.
|
||||||
|
|
||||||
|
## Update Strategies
|
||||||
|
|
||||||
|
In Kuberentes 1.7 and later, StatefulSet's `.spec.updateStrategy` field allows you to configure
|
||||||
|
and disable automated rolling updates for containers, labels, resource request/limits, and
|
||||||
|
annotations for the Pods in a StatefulSet.
|
||||||
|
|
||||||
|
### On Delete
|
||||||
|
|
||||||
|
The `OnDelete` update strategy implements the legacy (1.6 and prior) behavior. It is the default
|
||||||
|
strategy when `spec.updateStrategy` is left unspecified. When a StatefulSet's
|
||||||
|
`.spec.updateStrategy.type` is set to `OnDelete`, the StatefulSet controller will not automatically
|
||||||
|
update the Pods in a StatefulSet. Users must manually delete Pods to cause the controller to
|
||||||
|
create new Pods that reflect modifications made to a StatefulSet's `.spec.template`.
|
||||||
|
|
||||||
|
### Rolling Updates
|
||||||
|
|
||||||
|
The `RollingUpdate` update strategy implements automated, rolling update for the Pods in a
|
||||||
|
StatefulSet. When a StatefulSet's `.spec.updateStrategy.type` is set to `RollingUpdate`, the
|
||||||
|
StatefulSet controller will delete and recreate each Pod in the StatefulSet. It will proceed
|
||||||
|
in the same order as Pod termination (from the largest ordinal to the smallest), updating
|
||||||
|
each Pod one at a time. It will wait until an updated Pod is Running and Ready prior to
|
||||||
|
updating its predecessor.
|
||||||
|
|
||||||
|
#### Partitions
|
||||||
|
|
||||||
|
The `RollingUpdate` update strategy can be partitioned, by specifying a
|
||||||
|
`.spec.updateStrategy.rollingUpdate.partition`. If a partition is specified, all Pods with an
|
||||||
|
ordinal that is greater than or equal to the partition will be updated when the StatefulSet's
|
||||||
|
`.spec.template` is updated. All Pods with an ordinal that is less than the partition will not
|
||||||
|
be updated, and, even if they are deleted, they will be recreated at the previous version. If a
|
||||||
|
StatefulSet's `.spec.updateStrategy.rollingUpdate.partition` is greater than its `.spec.replicas`,
|
||||||
|
updates to its `.spec.template` will not be propagated to its Pods.
|
||||||
|
In most cases you will not need to use a partition, but they are useful if you want to stage an
|
||||||
|
update, roll out a canary, or perform a phased roll out.
|
||||||
|
|
||||||
|
{% endcapture %}
|
||||||
|
{% capture whatsnext %}
|
||||||
|
|
||||||
|
* Follow an example of [deploying a stateful application](/docs/tutorials/stateful-application/basic-stateful-set).
|
||||||
|
|
||||||
{% endcapture %}
|
{% endcapture %}
|
||||||
{% include templates/concept.md %}
|
{% include templates/concept.md %}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
---
|
---
|
||||||
assignees:
|
assignees:
|
||||||
- bprashanth
|
|
||||||
- enisoc
|
- enisoc
|
||||||
- erictune
|
- erictune
|
||||||
- foxish
|
- foxish
|
||||||
|
@ -11,10 +10,9 @@ title: StatefulSet Basics
|
||||||
---
|
---
|
||||||
|
|
||||||
{% capture overview %}
|
{% capture overview %}
|
||||||
This tutorial provides an introduction to manage applications with
|
This tutorial provides an introduction to managing applications with
|
||||||
[StatefulSets](/docs/concepts/abstractions/controllers/statefulsets/). It
|
[StatefulSets](/docs/concepts/abstractions/controllers/statefulsets/). It
|
||||||
demonstrates how to create, delete, scale, and update the container image of a
|
demonstrates how to create, delete, scale, and update the Pods of StatefulSets.
|
||||||
StatefulSet.
|
|
||||||
{% endcapture %}
|
{% endcapture %}
|
||||||
|
|
||||||
{% capture prerequisites %}
|
{% capture prerequisites %}
|
||||||
|
@ -40,7 +38,7 @@ StatefulSets are intended to be used with stateful applications and distributed
|
||||||
systems. However, the administration of stateful applications and
|
systems. However, the administration of stateful applications and
|
||||||
distributed systems on Kubernetes is a broad, complex topic. In order to
|
distributed systems on Kubernetes is a broad, complex topic. In order to
|
||||||
demonstrate the basic features of a StatefulSet, and to not conflate the former
|
demonstrate the basic features of a StatefulSet, and to not conflate the former
|
||||||
topic with the latter, you will deploy a simple web application using StatefulSets.
|
topic with the latter, you will deploy a simple web application using a StatefulSet.
|
||||||
|
|
||||||
After this tutorial, you will be familiar with the following.
|
After this tutorial, you will be familiar with the following.
|
||||||
|
|
||||||
|
@ -48,7 +46,7 @@ After this tutorial, you will be familiar with the following.
|
||||||
* How a StatefulSet manages its Pods
|
* How a StatefulSet manages its Pods
|
||||||
* How to delete a StatefulSet
|
* How to delete a StatefulSet
|
||||||
* How to scale a StatefulSet
|
* How to scale a StatefulSet
|
||||||
* How to update the container image of a StatefulSet's Pods
|
* How to update a StatefulSet's Pods
|
||||||
{% endcapture %}
|
{% endcapture %}
|
||||||
|
|
||||||
{% capture lessoncontent %}
|
{% capture lessoncontent %}
|
||||||
|
@ -56,9 +54,9 @@ After this tutorial, you will be familiar with the following.
|
||||||
|
|
||||||
Begin by creating a StatefulSet using the example below. It is similar to the
|
Begin by creating a StatefulSet using the example below. It is similar to the
|
||||||
example presented in the
|
example presented in the
|
||||||
[StatefulSets](/docs/concepts/abstractions/controllers/statefulsets/) concept. It creates
|
[StatefulSets](/docs/concepts/abstractions/controllers/statefulsets/) concept.
|
||||||
a [Headless Service](/docs/user-guide/services/#headless-services), `nginx`, to
|
It creates a [Headless Service](/docs/user-guide/services/#headless-services),
|
||||||
control the domain of the StatefulSet, `web`.
|
`nginx`, to publish the IP addresses of Pods in the StatefulSet, `web`.
|
||||||
|
|
||||||
{% include code.html language="yaml" file="web.yaml" ghlink="/docs/tutorials/stateful-application/web.yaml" %}
|
{% include code.html language="yaml" file="web.yaml" ghlink="/docs/tutorials/stateful-application/web.yaml" %}
|
||||||
|
|
||||||
|
@ -116,13 +114,12 @@ web-1 0/1 ContainerCreating 0 0s
|
||||||
web-1 1/1 Running 0 18s
|
web-1 1/1 Running 0 18s
|
||||||
```
|
```
|
||||||
|
|
||||||
Notice that the `web-0` Pod is launched and set to Pending prior to
|
Notice that the `web-1` Pod is not launched until the `web-0` Pod is
|
||||||
launching `web-1`. In fact, `web-1` is not launched until `web-0` is
|
|
||||||
[Running and Ready](/docs/user-guide/pod-states).
|
[Running and Ready](/docs/user-guide/pod-states).
|
||||||
|
|
||||||
## Pods in a StatefulSet
|
## Pods in a StatefulSet
|
||||||
Unlike Pods in other controllers, the Pods in a StatefulSet have a unique
|
|
||||||
ordinal index and a stable network identity.
|
Pods in a StatefulSet have a unique ordinal index and a stable network identity.
|
||||||
|
|
||||||
### Examining the Pod's Ordinal Index
|
### Examining the Pod's Ordinal Index
|
||||||
|
|
||||||
|
@ -138,12 +135,13 @@ web-1 1/1 Running 0 1m
|
||||||
|
|
||||||
As mentioned in the [StatefulSets](/docs/concepts/abstractions/controllers/statefulsets/)
|
As mentioned in the [StatefulSets](/docs/concepts/abstractions/controllers/statefulsets/)
|
||||||
concept, the Pods in a StatefulSet have a sticky, unique identity. This identity
|
concept, the Pods in a StatefulSet have a sticky, unique identity. This identity
|
||||||
is based on a unique ordinal index that is assigned to each Pod by the Stateful
|
is based on a unique ordinal index that is assigned to each Pod by the
|
||||||
Set controller. The Pods' names take the form
|
StatefulSet controller. The Pods' names take the form
|
||||||
`<statefulset name>-<ordinal index>`. Since the `web` StatefulSet has two
|
`<statefulset name>-<ordinal index>`. Since the `web` StatefulSet has two
|
||||||
replicas, it creates two Pods, `web-0` and `web-1`.
|
replicas, it creates two Pods, `web-0` and `web-1`.
|
||||||
|
|
||||||
### Using Stable Network Identities
|
### Using Stable Network Identities
|
||||||
|
|
||||||
Each Pod has a stable hostname based on its ordinal index. Use
|
Each Pod has a stable hostname based on its ordinal index. Use
|
||||||
[`kubectl exec`](/docs/user-guide/kubectl/v1.6/#exec) to execute the
|
[`kubectl exec`](/docs/user-guide/kubectl/v1.6/#exec) to execute the
|
||||||
`hostname` command in each Pod.
|
`hostname` command in each Pod.
|
||||||
|
@ -264,9 +262,9 @@ www-web-0 Bound pvc-15c268c7-b507-11e6-932f-42010a800002 1Gi RWO
|
||||||
www-web-1 Bound pvc-15c79307-b507-11e6-932f-42010a800002 1Gi RWO 48s
|
www-web-1 Bound pvc-15c79307-b507-11e6-932f-42010a800002 1Gi RWO 48s
|
||||||
```
|
```
|
||||||
The StatefulSet controller created two PersistentVolumeClaims that are
|
The StatefulSet controller created two PersistentVolumeClaims that are
|
||||||
bound to two [PersistentVolumes](/docs/concepts/storage/volumes/). As the cluster used
|
bound to two [PersistentVolumes](/docs/concepts/storage/volumes/). As the
|
||||||
in this tutorial is configured to dynamically provision PersistentVolumes, the
|
cluster used in this tutorial is configured to dynamically provision
|
||||||
PersistentVolumes were created and bound automatically.
|
PersistentVolumes, the PersistentVolumes were created and bound automatically.
|
||||||
|
|
||||||
The NGINX webservers, by default, will serve an index file at
|
The NGINX webservers, by default, will serve an index file at
|
||||||
`/usr/share/nginx/html/index.html`. The `volumeMounts` field in the
|
`/usr/share/nginx/html/index.html`. The `volumeMounts` field in the
|
||||||
|
@ -331,10 +329,10 @@ web-1
|
||||||
```
|
```
|
||||||
|
|
||||||
Even though `web-0` and `web-1` were rescheduled, they continue to serve their
|
Even though `web-0` and `web-1` were rescheduled, they continue to serve their
|
||||||
hostnames because the PersistentVolumes associated with their Persistent
|
hostnames because the PersistentVolumes associated with their
|
||||||
Volume Claims are remounted to their `volumeMount`s. No matter what node `web-0`
|
PersistentVolumeClaims are remounted to their `volumeMount`s. No matter what
|
||||||
and `web-1` are scheduled on, their PersistentVolumes will be mounted to the
|
node `web-0`and `web-1` are scheduled on, their PersistentVolumes will be
|
||||||
appropriate mount points.
|
mounted to the appropriate mount points.
|
||||||
|
|
||||||
## Scaling a StatefulSet
|
## Scaling a StatefulSet
|
||||||
Scaling a StatefulSet refers to increasing or decreasing the number of replicas.
|
Scaling a StatefulSet refers to increasing or decreasing the number of replicas.
|
||||||
|
@ -355,7 +353,7 @@ In another terminal window, use `kubectl scale` to scale the number of replicas
|
||||||
to 5.
|
to 5.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl scale statefulset web --replicas=5
|
kubectl scale sts web --replicas=5
|
||||||
statefulset "web" scaled
|
statefulset "web" scaled
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -397,10 +395,10 @@ kubectl get pods -w -l app=nginx
|
||||||
```
|
```
|
||||||
|
|
||||||
In another terminal, use `kubectl patch` to scale the StatefulSet back down to
|
In another terminal, use `kubectl patch` to scale the StatefulSet back down to
|
||||||
3 replicas.
|
three replicas.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl patch statefulset web -p '{"spec":{"replicas":3}}'
|
kubectl patch sts web -p '{"spec":{"replicas":3}}'
|
||||||
"web" patched
|
"web" patched
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -424,8 +422,8 @@ web-3 1/1 Terminating 0 42s
|
||||||
|
|
||||||
### Ordered Pod Termination
|
### Ordered Pod Termination
|
||||||
|
|
||||||
The controller deleted one Pod at a time, with respect to its ordinal index,
|
The controller deleted one Pod at a time, in reverse order with respect to its
|
||||||
in reverse order, and it waited for each to be completely shutdown before
|
ordinal index, and it waited for each to be completely shutdown before
|
||||||
deleting the next.
|
deleting the next.
|
||||||
|
|
||||||
Get the StatefulSet's PersistentVolumeClaims.
|
Get the StatefulSet's PersistentVolumeClaims.
|
||||||
|
@ -445,18 +443,22 @@ There are still five PersistentVolumeClaims and five PersistentVolumes.
|
||||||
When exploring a Pod's [stable storage](#stable-storage), we saw that the
|
When exploring a Pod's [stable storage](#stable-storage), we saw that the
|
||||||
PersistentVolumes mounted to the Pods of a StatefulSet are not deleted when
|
PersistentVolumes mounted to the Pods of a StatefulSet are not deleted when
|
||||||
the StatefulSet's Pods are deleted. This is still true when Pod deletion is
|
the StatefulSet's Pods are deleted. This is still true when Pod deletion is
|
||||||
caused by scaling the StatefulSet down. This feature can be used to facilitate
|
caused by scaling the StatefulSet down.
|
||||||
upgrading the container images of Pods in a StatefulSet.
|
|
||||||
|
|
||||||
## Updating Containers
|
## Updating StatefulSets
|
||||||
As demonstrated in the [Scaling a StatefulSet](#scaling-a-statefulset) section,
|
|
||||||
the `replicas` field of a StatefulSet is mutable. The only other field of a
|
|
||||||
StatefulSet that can be updated is the `spec.template.containers` field.
|
|
||||||
|
|
||||||
StatefulSet currently *does not* support automated image upgrade. However, you
|
In Kubernetes 1.7, the StatefulSet controller supports automated updates. The
|
||||||
can update the `image` field of any container in the podTemplate and delete
|
strategy used is determined by the `spec.updateStrategy` field of the
|
||||||
StatefulSet's Pods one by one, the StatefulSet controller will recreate
|
StatefulSet API Object. This feature can be used to upgrade the container
|
||||||
each Pod with the new image.
|
images, resource requests and/or limits, labels, and annotations of the Pods in a
|
||||||
|
StatefulSet. There are two valid update strategies, `OnDelete` and
|
||||||
|
`RollingUpdate`.
|
||||||
|
|
||||||
|
### On Delete
|
||||||
|
The `OnDelete` update strategy implements the legacy (prior to 1.7) behavior,
|
||||||
|
and it is the default update strategy. When you select this update strategy,
|
||||||
|
the StatefulSet controller will not automatically update Pods when a
|
||||||
|
modification is made to the StatefulSet's `.spec.template` field.
|
||||||
|
|
||||||
Patch the container image for the `web` StatefulSet.
|
Patch the container image for the `web` StatefulSet.
|
||||||
|
|
||||||
|
@ -472,7 +474,7 @@ kubectl delete pod web-0
|
||||||
pod "web-0" deleted
|
pod "web-0" deleted
|
||||||
```
|
```
|
||||||
|
|
||||||
Watch `web-0`, and wait for the Pod to transition to Running and Ready.
|
Watch the `web-0` Pod, and wait for it to transition to Running and Ready.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get pod web-0 -w
|
kubectl get pod web-0 -w
|
||||||
|
@ -488,7 +490,7 @@ web-0 0/1 ContainerCreating 0 0s
|
||||||
web-0 1/1 Running 0 3s
|
web-0 1/1 Running 0 3s
|
||||||
```
|
```
|
||||||
|
|
||||||
Get the Pods to view their container images.
|
Get the `web` StatefulSet's Pods to view their container images.
|
||||||
|
|
||||||
```shell{% raw %}
|
```shell{% raw %}
|
||||||
kubectl get pod -l app=nginx -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[0].image}{"\n"}{end}'
|
kubectl get pod -l app=nginx -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[0].image}{"\n"}{end}'
|
||||||
|
@ -497,8 +499,8 @@ web-1 gcr.io/google_containers/nginx-slim:0.8
|
||||||
web-2 gcr.io/google_containers/nginx-slim:0.8
|
web-2 gcr.io/google_containers/nginx-slim:0.8
|
||||||
{% endraw %}```
|
{% endraw %}```
|
||||||
|
|
||||||
`web-0` has had its image updated. Complete the update by deleting the remaining
|
`web-0` has had its image updated, but `web-0` and `web-1` still have the original
|
||||||
Pods.
|
image. Complete the update by deleting the remaining Pods.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl delete pod web-1 web-2
|
kubectl delete pod web-1 web-2
|
||||||
|
@ -506,7 +508,7 @@ pod "web-1" deleted
|
||||||
pod "web-2" deleted
|
pod "web-2" deleted
|
||||||
```
|
```
|
||||||
|
|
||||||
Watch the Pods, and wait for all of them to transition to Running and Ready.
|
Watch the StatefulSet's Pods, and wait for all of them to transition to Running and Ready.
|
||||||
|
|
||||||
```
|
```
|
||||||
kubectl get pods -w -l app=nginx
|
kubectl get pods -w -l app=nginx
|
||||||
|
@ -540,6 +542,261 @@ web-2 gcr.io/google_containers/nginx-slim:0.7
|
||||||
|
|
||||||
All the Pods in the StatefulSet are now running a new container image.
|
All the Pods in the StatefulSet are now running a new container image.
|
||||||
|
|
||||||
|
### Rolling Update
|
||||||
|
|
||||||
|
The `RollingUpdate` update strategy will update all Pods in a StatefulSet, in
|
||||||
|
reverse ordinal order, while respecting the StatefulSet guarantees.
|
||||||
|
|
||||||
|
Patch the `web` StatefulSet to apply the `RollingUpdate` update strategy.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate"}}}
|
||||||
|
statefulset "web" patched
|
||||||
|
```
|
||||||
|
|
||||||
|
In one terminal window, patch the `web` StatefulSet to change the container
|
||||||
|
image again.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"gcr.io/google_containers/nginx-slim:0.8"}]'
|
||||||
|
statefulset "web" patched
|
||||||
|
```
|
||||||
|
|
||||||
|
In another terminal, watch the Pods in the StatefulSet.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl get po -l app=nginx -w
|
||||||
|
NAME READY STATUS RESTARTS AGE
|
||||||
|
web-0 1/1 Running 0 7m
|
||||||
|
web-1 1/1 Running 0 7m
|
||||||
|
web-2 1/1 Running 0 8m
|
||||||
|
web-2 1/1 Terminating 0 8m
|
||||||
|
web-2 1/1 Terminating 0 8m
|
||||||
|
web-2 0/1 Terminating 0 8m
|
||||||
|
web-2 0/1 Terminating 0 8m
|
||||||
|
web-2 0/1 Terminating 0 8m
|
||||||
|
web-2 0/1 Terminating 0 8m
|
||||||
|
web-2 0/1 Pending 0 0s
|
||||||
|
web-2 0/1 Pending 0 0s
|
||||||
|
web-2 0/1 ContainerCreating 0 0s
|
||||||
|
web-2 1/1 Running 0 19s
|
||||||
|
web-1 1/1 Terminating 0 8m
|
||||||
|
web-1 0/1 Terminating 0 8m
|
||||||
|
web-1 0/1 Terminating 0 8m
|
||||||
|
web-1 0/1 Terminating 0 8m
|
||||||
|
web-1 0/1 Pending 0 0s
|
||||||
|
web-1 0/1 Pending 0 0s
|
||||||
|
web-1 0/1 ContainerCreating 0 0s
|
||||||
|
web-1 1/1 Running 0 6s
|
||||||
|
web-0 1/1 Terminating 0 7m
|
||||||
|
web-0 1/1 Terminating 0 7m
|
||||||
|
web-0 0/1 Terminating 0 7m
|
||||||
|
web-0 0/1 Terminating 0 7m
|
||||||
|
web-0 0/1 Terminating 0 7m
|
||||||
|
web-0 0/1 Terminating 0 7m
|
||||||
|
web-0 0/1 Pending 0 0s
|
||||||
|
web-0 0/1 Pending 0 0s
|
||||||
|
web-0 0/1 ContainerCreating 0 0s
|
||||||
|
web-0 1/1 Running 0 10s
|
||||||
|
```
|
||||||
|
|
||||||
|
The Pods in the StatefulSet are updated in reverse ordinal order. The
|
||||||
|
StatefulSet controller terminates each Pod, and waits for it to transition to Running and
|
||||||
|
Ready prior to updating the next Pod. Note that, even though the StatefulSet
|
||||||
|
controller will not proceed to update the next Pod until its ordinal successor
|
||||||
|
is Running and Ready, it will restore any Pod that fails during the update to
|
||||||
|
its current version. Pods that have already received the update will be
|
||||||
|
restored to the updated version, and Pods that have not yet received the
|
||||||
|
update will be restored to the previous version. In this way, the controller
|
||||||
|
attempts to continue to keep the application healthy and the update consistent
|
||||||
|
in the presence of intermittent failures.
|
||||||
|
|
||||||
|
Get the Pods to view their container images.
|
||||||
|
|
||||||
|
```shell{% raw %}
|
||||||
|
for p in 0 1 2; do kubectl get po web-$p --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
|
||||||
|
gcr.io/google_containers/nginx-slim:0.8
|
||||||
|
gcr.io/google_containers/nginx-slim:0.8
|
||||||
|
gcr.io/google_containers/nginx-slim:0.8
|
||||||
|
{% endraw %}
|
||||||
|
```
|
||||||
|
|
||||||
|
All the Pods in the StatefulSet are now running the previous container image.
|
||||||
|
|
||||||
|
**Tip** You can also use `kubectl rollout status sts/<name>` to view
|
||||||
|
the status of a rolling update.
|
||||||
|
|
||||||
|
#### Staging an Update
|
||||||
|
You can stage an update to a StatefulSet by using the `partition` parameter of
|
||||||
|
the `RollingUpdate` update strategy. A staged update will keep all of the Pods
|
||||||
|
in the StatefulSet at the current version while allowing mutations to the
|
||||||
|
StatefulSet's `.spec.template`.
|
||||||
|
|
||||||
|
Patch the `web` StatefulSet to add a partition to the `updateStrategy` field.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}'
|
||||||
|
statefulset "web" patched
|
||||||
|
```
|
||||||
|
|
||||||
|
Patch the StatefulSet again to change the container's image.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"gcr.io/google_containers/nginx-slim:0.7"}]'
|
||||||
|
statefulset "web" patched
|
||||||
|
```
|
||||||
|
|
||||||
|
Delete a Pod in the StatefulSet.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl delete po web-2
|
||||||
|
pod "web-2" deleted
|
||||||
|
```
|
||||||
|
|
||||||
|
Wait for the Pod to be Running and Ready.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl get po -lapp=nginx -w
|
||||||
|
NAME READY STATUS RESTARTS AGE
|
||||||
|
web-0 1/1 Running 0 4m
|
||||||
|
web-1 1/1 Running 0 4m
|
||||||
|
web-2 0/1 ContainerCreating 0 11s
|
||||||
|
web-2 1/1 Running 0 18s
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the Pod's container.
|
||||||
|
|
||||||
|
```shell{% raw %}
|
||||||
|
get po web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
|
||||||
|
gcr.io/google_containers/nginx-slim:0.8
|
||||||
|
{% endraw %}
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice that, even though the update strategy is `RollingUpdate` the StatefulSet
|
||||||
|
controller restored the Pod with its original container. This is because the
|
||||||
|
ordinal of the Pod is less than the `partition` specified by the
|
||||||
|
`updateStrategy`.
|
||||||
|
|
||||||
|
#### Rolling Out a Canary
|
||||||
|
You can roll out a canary to test a modification by decrementing the `partition`
|
||||||
|
you specified [above](#staging-an-update).
|
||||||
|
|
||||||
|
Patch the StatefulSet to decrement the partition.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":2}}}}'
|
||||||
|
statefulset "web" patched
|
||||||
|
```
|
||||||
|
|
||||||
|
Wait for `web-2` to be Running and Ready.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl get po -lapp=nginx -w
|
||||||
|
NAME READY STATUS RESTARTS AGE
|
||||||
|
web-0 1/1 Running 0 4m
|
||||||
|
web-1 1/1 Running 0 4m
|
||||||
|
web-2 0/1 ContainerCreating 0 11s
|
||||||
|
web-2 1/1 Running 0 18s
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the Pod's container.
|
||||||
|
|
||||||
|
```shell{% raw %}
|
||||||
|
kubectl get po web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
|
||||||
|
gcr.io/google_containers/nginx-slim:0.7
|
||||||
|
{% endraw %}
|
||||||
|
```
|
||||||
|
|
||||||
|
When you changed the `partition`, the StatefulSet controller automatically
|
||||||
|
updated the `web-2` Pod because the Pod's ordinal was less than or equal to
|
||||||
|
the `partition`.
|
||||||
|
|
||||||
|
Delete the `web-1` Pod.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl delete po web-1
|
||||||
|
pod "web-1" deleted
|
||||||
|
```
|
||||||
|
|
||||||
|
Wait for the `web-1` Pod to be Running and Ready.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl get po -lapp=nginx -w
|
||||||
|
NAME READY STATUS RESTARTS AGE
|
||||||
|
web-0 1/1 Running 0 6m
|
||||||
|
web-1 0/1 Terminating 0 6m
|
||||||
|
web-2 1/1 Running 0 2m
|
||||||
|
web-1 0/1 Terminating 0 6m
|
||||||
|
web-1 0/1 Terminating 0 6m
|
||||||
|
web-1 0/1 Terminating 0 6m
|
||||||
|
web-1 0/1 Pending 0 0s
|
||||||
|
web-1 0/1 Pending 0 0s
|
||||||
|
web-1 0/1 ContainerCreating 0 0s
|
||||||
|
web-1 1/1 Running 0 18s
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the `web-1` Pods container.
|
||||||
|
|
||||||
|
```shell{% raw %}
|
||||||
|
get po web-1 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
|
||||||
|
gcr.io/google_containers/nginx-slim:0.8
|
||||||
|
{% endraw %}
|
||||||
|
```
|
||||||
|
`web-1` was restored to its original configuration because the Pod's ordinal
|
||||||
|
was less than the partition. When a partition is specified, all Pods with an
|
||||||
|
ordinal that is greater than or equal to the partition will be updated when the
|
||||||
|
StatefulSet's `.spec.template` is updated. If a Pod that has an ordinal less
|
||||||
|
than the partition is deleted or otherwise terminated, it will be restored to
|
||||||
|
its original configuration.
|
||||||
|
|
||||||
|
#### Phased Roll Outs
|
||||||
|
You can perform a phased roll out (e.g. a linear, geometric, or exponential
|
||||||
|
roll out) using a partitioned rolling update in a similar manner to how you
|
||||||
|
rolled out a [canary](#rolling-out-a-canary). To perform a phased roll out, set
|
||||||
|
the `partition` to the ordinal at which you want the controller to pause the
|
||||||
|
update.
|
||||||
|
|
||||||
|
The partition is currently set to `2`. Set the partition to `0`.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":0}}}}'
|
||||||
|
statefulset "web" patched
|
||||||
|
```
|
||||||
|
|
||||||
|
Wait for all of the Pods in the StatefulSet to become Running and Ready.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl get po -lapp=nginx -w
|
||||||
|
NAME READY STATUS RESTARTS AGE
|
||||||
|
web-0 1/1 Running 0 3m
|
||||||
|
web-1 0/1 ContainerCreating 0 11s
|
||||||
|
web-2 1/1 Running 0 2m
|
||||||
|
web-1 1/1 Running 0 18s
|
||||||
|
web-0 1/1 Terminating 0 3m
|
||||||
|
web-0 1/1 Terminating 0 3m
|
||||||
|
web-0 0/1 Terminating 0 3m
|
||||||
|
web-0 0/1 Terminating 0 3m
|
||||||
|
web-0 0/1 Terminating 0 3m
|
||||||
|
web-0 0/1 Terminating 0 3m
|
||||||
|
web-0 0/1 Pending 0 0s
|
||||||
|
web-0 0/1 Pending 0 0s
|
||||||
|
web-0 0/1 ContainerCreating 0 0s
|
||||||
|
web-0 1/1 Running 0 3s
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the Pod's containers.
|
||||||
|
|
||||||
|
```shell{% raw %}
|
||||||
|
for p in 0 1 2; do kubectl get po web-$p --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
|
||||||
|
gcr.io/google_containers/nginx-slim:0.7
|
||||||
|
gcr.io/google_containers/nginx-slim:0.7
|
||||||
|
gcr.io/google_containers/nginx-slim:0.7
|
||||||
|
{% endraw %}
|
||||||
|
```
|
||||||
|
|
||||||
|
By moving the `partition` to `0`, you allowed the StatefulSet controller to
|
||||||
|
continue the update process.
|
||||||
|
|
||||||
## Deleting StatefulSets
|
## Deleting StatefulSets
|
||||||
|
|
||||||
StatefulSet supports both Non-Cascading and Cascading deletion. In a
|
StatefulSet supports both Non-Cascading and Cascading deletion. In a
|
||||||
|
@ -596,7 +853,7 @@ As the `web` StatefulSet has been deleted, `web-0` has not been relaunched.
|
||||||
|
|
||||||
In one terminal, watch the StatefulSet's Pods.
|
In one terminal, watch the StatefulSet's Pods.
|
||||||
|
|
||||||
```
|
```shell
|
||||||
kubectl get pods -w -l app=nginx
|
kubectl get pods -w -l app=nginx
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -733,6 +990,131 @@ kubectl delete statefulset web
|
||||||
statefulset "web" deleted
|
statefulset "web" deleted
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Pod Management Policy
|
||||||
|
|
||||||
|
For some distributed systems, the StatefulSet ordering guarantees are
|
||||||
|
unnecessary and/or undesirable. These systems require only uniqueness and
|
||||||
|
identity. To address this, in Kubernetes 1.7, we introduced
|
||||||
|
`.spec.podManagementPolicy` to the StatefulSet API Object.
|
||||||
|
|
||||||
|
### OrderedReady Pod Management
|
||||||
|
|
||||||
|
`OrderedReady` pod management is the default for StatefulSets. It tells the
|
||||||
|
StatefulSet controller to respect the ordering guarantees demonstrated
|
||||||
|
above.
|
||||||
|
|
||||||
|
### Parallel Pod Management
|
||||||
|
|
||||||
|
`Parallel` pod management tells the StatefulSet controller to launch or
|
||||||
|
terminate all Pods in parallel, and to not wait for Pods to becoming Running
|
||||||
|
and Ready or completely terminated prior to launching or terminating another
|
||||||
|
Pod.
|
||||||
|
|
||||||
|
{% include code.html language="yaml" file="webp.yaml" ghlink="/docs/tutorials/stateful-application/webp.yaml" %}
|
||||||
|
|
||||||
|
Download the example above, and save it to a file named `webp.yaml`
|
||||||
|
|
||||||
|
This manifest is identical to the one you
|
||||||
|
[downloaded above](creating-a-statefulset) except that the `.spec.podManagementPolicy`
|
||||||
|
of the `web` StatefulSet is set to `Parallel`.
|
||||||
|
|
||||||
|
In one terminal, watch the Pods in the StatefulSet.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl get po -lapp=nginx -w
|
||||||
|
```
|
||||||
|
|
||||||
|
In another terminal, create the StatefulSet and Service in the manifest.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl create -f webp.yaml
|
||||||
|
service "nginx" created
|
||||||
|
statefulset "web" created
|
||||||
|
```
|
||||||
|
|
||||||
|
Examine the output of the `kubectl get` command that you executed in the first terminal.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl get po -lapp=nginx -w
|
||||||
|
NAME READY STATUS RESTARTS AGE
|
||||||
|
web-0 0/1 Pending 0 0s
|
||||||
|
web-0 0/1 Pending 0 0s
|
||||||
|
web-1 0/1 Pending 0 0s
|
||||||
|
web-1 0/1 Pending 0 0s
|
||||||
|
web-0 0/1 ContainerCreating 0 0s
|
||||||
|
web-1 0/1 ContainerCreating 0 0s
|
||||||
|
web-0 1/1 Running 0 10s
|
||||||
|
web-1 1/1 Running 0 10s
|
||||||
|
```
|
||||||
|
|
||||||
|
The StatefulSet controller launched both `web-0` and `web-1` at the same time.
|
||||||
|
|
||||||
|
Keep the second terminal open, and, in another terminal window scale the
|
||||||
|
StatefulSet.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl scale statefulset/web --replicas=4
|
||||||
|
statefulset "web" scaled
|
||||||
|
```
|
||||||
|
|
||||||
|
Examine the output of the terminal where the `kubectl get` command is running.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
web-3 0/1 Pending 0 0s
|
||||||
|
web-3 0/1 Pending 0 0s
|
||||||
|
web-3 0/1 Pending 0 7s
|
||||||
|
web-3 0/1 ContainerCreating 0 7s
|
||||||
|
web-2 1/1 Running 0 10s
|
||||||
|
web-3 1/1 Running 0 26s
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
The StatefulSet controller launched two new Pods, and it did not wait for
|
||||||
|
the first to become Running and Ready prior to launching the second.
|
||||||
|
|
||||||
|
Keep this terminal open, and in another terminal delete the `web` StatefulSet.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl delete sts web
|
||||||
|
```
|
||||||
|
|
||||||
|
Again, examine the output of the `kubectl get` command running in the other terminal.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
web-3 1/1 Terminating 0 9m
|
||||||
|
web-2 1/1 Terminating 0 9m
|
||||||
|
web-3 1/1 Terminating 0 9m
|
||||||
|
web-2 1/1 Terminating 0 9m
|
||||||
|
web-1 1/1 Terminating 0 44m
|
||||||
|
web-0 1/1 Terminating 0 44m
|
||||||
|
web-0 0/1 Terminating 0 44m
|
||||||
|
web-3 0/1 Terminating 0 9m
|
||||||
|
web-2 0/1 Terminating 0 9m
|
||||||
|
web-1 0/1 Terminating 0 44m
|
||||||
|
web-0 0/1 Terminating 0 44m
|
||||||
|
web-2 0/1 Terminating 0 9m
|
||||||
|
web-2 0/1 Terminating 0 9m
|
||||||
|
web-2 0/1 Terminating 0 9m
|
||||||
|
web-1 0/1 Terminating 0 44m
|
||||||
|
web-1 0/1 Terminating 0 44m
|
||||||
|
web-1 0/1 Terminating 0 44m
|
||||||
|
web-0 0/1 Terminating 0 44m
|
||||||
|
web-0 0/1 Terminating 0 44m
|
||||||
|
web-0 0/1 Terminating 0 44m
|
||||||
|
web-3 0/1 Terminating 0 9m
|
||||||
|
web-3 0/1 Terminating 0 9m
|
||||||
|
web-3 0/1 Terminating 0 9m
|
||||||
|
```
|
||||||
|
|
||||||
|
The StatefulSet controller deletes all Pods concurrently, it does not wait for
|
||||||
|
a Pod's ordinal successor to terminate prior to deleting that Pod.
|
||||||
|
|
||||||
|
Close the terminal where the `kubectl get` command is running and delete the `nginx`
|
||||||
|
Service.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl delete svc nginx
|
||||||
|
```
|
||||||
{% endcapture %}
|
{% endcapture %}
|
||||||
|
|
||||||
{% capture cleanup %}
|
{% capture cleanup %}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: nginx
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
name: web
|
||||||
|
clusterIP: None
|
||||||
|
selector:
|
||||||
|
app: nginx
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1beta1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: web
|
||||||
|
spec:
|
||||||
|
serviceName: "nginx"
|
||||||
|
podManagementPolicy: "Parallel"
|
||||||
|
replicas: 2
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: gcr.io/google_containers/nginx-slim:0.8
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
name: web
|
||||||
|
volumeMounts:
|
||||||
|
- name: www
|
||||||
|
mountPath: /usr/share/nginx/html
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: www
|
||||||
|
spec:
|
||||||
|
accessModes: [ "ReadWriteOnce" ]
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
|
@ -332,6 +332,7 @@ func TestExampleObjectSchemas(t *testing.T) {
|
||||||
"mysql-configmap": {&api.ConfigMap{}},
|
"mysql-configmap": {&api.ConfigMap{}},
|
||||||
"mysql-statefulset": {&apps.StatefulSet{}},
|
"mysql-statefulset": {&apps.StatefulSet{}},
|
||||||
"web": {&api.Service{}, &apps.StatefulSet{}},
|
"web": {&api.Service{}, &apps.StatefulSet{}},
|
||||||
|
"webp": {&api.Service{}, &apps.StatefulSet{}},
|
||||||
"zookeeper": {&api.Service{}, &api.ConfigMap{}, &policy.PodDisruptionBudget{}, &apps.StatefulSet{}},
|
"zookeeper": {&api.Service{}, &api.ConfigMap{}, &policy.PodDisruptionBudget{}, &apps.StatefulSet{}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue