Revise StatefulSet Basics
- fix markdown - separate commands from their output - don't highlight sample output as if it were Bourne shell code - add note shortcodes where appropriate - update link targets - miscellaneous other tidying
This commit is contained in:
@@ -13,13 +13,14 @@ weight: 10
|
|||||||
|
|
||||||
<!-- overview -->
|
<!-- overview -->
|
||||||
This tutorial provides an introduction to managing applications with
|
This tutorial provides an introduction to managing applications with
|
||||||
[StatefulSets](/docs/concepts/workloads/controllers/statefulset/). It
|
{{< glossary_tooltip text="StatefulSets" term_id="statefulset" >}}.
|
||||||
demonstrates how to create, delete, scale, and update the Pods of StatefulSets.
|
It demonstrates how to create, delete, scale, and update the Pods of StatefulSets.
|
||||||
|
|
||||||
|
|
||||||
## {{% heading "prerequisites" %}}
|
## {{% heading "prerequisites" %}}
|
||||||
|
|
||||||
Before you begin this tutorial, you should familiarize yourself with the
|
Before you begin this tutorial, you should familiarize yourself with the
|
||||||
following Kubernetes concepts.
|
following Kubernetes concepts:
|
||||||
|
|
||||||
* [Pods](/docs/concepts/workloads/pods/)
|
* [Pods](/docs/concepts/workloads/pods/)
|
||||||
* [Cluster DNS](/docs/concepts/services-networking/dns-pod-service/)
|
* [Cluster DNS](/docs/concepts/services-networking/dns-pod-service/)
|
||||||
@@ -27,12 +28,14 @@ following Kubernetes concepts.
|
|||||||
* [PersistentVolumes](/docs/concepts/storage/persistent-volumes/)
|
* [PersistentVolumes](/docs/concepts/storage/persistent-volumes/)
|
||||||
* [PersistentVolume Provisioning](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/persistent-volume-provisioning/)
|
* [PersistentVolume Provisioning](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/persistent-volume-provisioning/)
|
||||||
* [StatefulSets](/docs/concepts/workloads/controllers/statefulset/)
|
* [StatefulSets](/docs/concepts/workloads/controllers/statefulset/)
|
||||||
* [kubectl CLI](/docs/user-guide/kubectl/)
|
* The [kubectl](/docs/reference/kubectl/kubectl/) command line tool
|
||||||
|
|
||||||
|
{{< note >}}
|
||||||
This tutorial assumes that your cluster is configured to dynamically provision
|
This tutorial assumes that your cluster is configured to dynamically provision
|
||||||
PersistentVolumes. If your cluster is not configured to do so, you
|
PersistentVolumes. If your cluster is not configured to do so, you
|
||||||
will have to manually provision two 1 GiB volumes prior to starting this
|
will have to manually provision two 1 GiB volumes prior to starting this
|
||||||
tutorial.
|
tutorial.
|
||||||
|
{{< /note >}}
|
||||||
|
|
||||||
## {{% heading "objectives" %}}
|
## {{% heading "objectives" %}}
|
||||||
|
|
||||||
@@ -57,7 +60,7 @@ 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/workloads/controllers/statefulset/) concept.
|
[StatefulSets](/docs/concepts/workloads/controllers/statefulset/) concept.
|
||||||
It creates a [Headless Service](/docs/concepts/services-networking/service/#headless-services),
|
It creates a [headless Service](/docs/concepts/services-networking/service/#headless-services),
|
||||||
`nginx`, to publish the IP addresses of Pods in the StatefulSet, `web`.
|
`nginx`, to publish the IP addresses of Pods in the StatefulSet, `web`.
|
||||||
|
|
||||||
{{< codenew file="application/web/web.yaml" >}}
|
{{< codenew file="application/web/web.yaml" >}}
|
||||||
@@ -74,37 +77,45 @@ kubectl get pods -w -l app=nginx
|
|||||||
|
|
||||||
In the second terminal, use
|
In the second terminal, use
|
||||||
[`kubectl apply`](/docs/reference/generated/kubectl/kubectl-commands/#apply) to create the
|
[`kubectl apply`](/docs/reference/generated/kubectl/kubectl-commands/#apply) to create the
|
||||||
Headless Service and StatefulSet defined in `web.yaml`.
|
headless Service and StatefulSet defined in `web.yaml`.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl apply -f web.yaml
|
kubectl apply -f web.yaml
|
||||||
|
```
|
||||||
|
```
|
||||||
service/nginx created
|
service/nginx created
|
||||||
statefulset.apps/web created
|
statefulset.apps/web created
|
||||||
```
|
```
|
||||||
|
|
||||||
The command above creates two Pods, each running an
|
The command above creates two Pods, each running an
|
||||||
[NGINX](https://www.nginx.com) webserver. Get the `nginx` Service and the
|
[NGINX](https://www.nginx.com) webserver. Get the `nginx` Service...
|
||||||
`web` StatefulSet to verify that they were created successfully.
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get service nginx
|
kubectl get service nginx
|
||||||
|
```
|
||||||
|
```
|
||||||
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||||
nginx ClusterIP None <none> 80/TCP 12s
|
nginx ClusterIP None <none> 80/TCP 12s
|
||||||
|
```
|
||||||
|
...then get the `web` StatefulSet, to verify that both were created successfully:
|
||||||
|
```shell
|
||||||
kubectl get statefulset web
|
kubectl get statefulset web
|
||||||
|
```
|
||||||
|
```
|
||||||
NAME DESIRED CURRENT AGE
|
NAME DESIRED CURRENT AGE
|
||||||
web 2 1 20s
|
web 2 1 20s
|
||||||
```
|
```
|
||||||
|
|
||||||
### Ordered Pod Creation
|
### Ordered Pod Creation
|
||||||
|
|
||||||
For a StatefulSet with N replicas, when Pods are being deployed, they are
|
For a StatefulSet with _n_ replicas, when Pods are being deployed, they are
|
||||||
created sequentially, in order from {0..N-1}. Examine the output of the
|
created sequentially, ordered from _{0..n-1}_. Examine the output of the
|
||||||
`kubectl get` command in the first terminal. Eventually, the output will
|
`kubectl get` command in the first terminal. Eventually, the output will
|
||||||
look like the example below.
|
look like the example below.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get pods -w -l app=nginx
|
kubectl get pods -w -l app=nginx
|
||||||
|
```
|
||||||
|
```
|
||||||
NAME READY STATUS RESTARTS AGE
|
NAME READY STATUS RESTARTS AGE
|
||||||
web-0 0/1 Pending 0 0s
|
web-0 0/1 Pending 0 0s
|
||||||
web-0 0/1 Pending 0 0s
|
web-0 0/1 Pending 0 0s
|
||||||
@@ -117,7 +128,8 @@ web-1 1/1 Running 0 18s
|
|||||||
```
|
```
|
||||||
|
|
||||||
Notice that the `web-1` Pod is not launched until the `web-0` Pod is
|
Notice that the `web-1` Pod is not launched until the `web-0` Pod is
|
||||||
[Running and Ready](/docs/user-guide/pod-states).
|
_Running_ (see [Pod Phase](/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase))
|
||||||
|
and _Ready_ (see `type` in [Pod Conditions](/docs/concepts/workloads/pods/pod-lifecycle/#pod-conditions)).
|
||||||
|
|
||||||
## Pods in a StatefulSet
|
## Pods in a StatefulSet
|
||||||
|
|
||||||
@@ -125,31 +137,34 @@ 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
|
||||||
|
|
||||||
Get the StatefulSet's Pods.
|
Get the StatefulSet's Pods:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get pods -l app=nginx
|
kubectl get pods -l app=nginx
|
||||||
|
```
|
||||||
|
```
|
||||||
NAME READY STATUS RESTARTS AGE
|
NAME READY STATUS RESTARTS AGE
|
||||||
web-0 1/1 Running 0 1m
|
web-0 1/1 Running 0 1m
|
||||||
web-1 1/1 Running 0 1m
|
web-1 1/1 Running 0 1m
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
As mentioned in the [StatefulSets](/docs/concepts/workloads/controllers/statefulset/)
|
As mentioned in the [StatefulSets](/docs/concepts/workloads/controllers/statefulset/)
|
||||||
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
|
is based on a unique ordinal index that is assigned to each Pod by the
|
||||||
StatefulSet controller. The Pods' names take the form
|
StatefulSet {{< glossary_tooltip term_id="controller" text="controller">}}.
|
||||||
`<statefulset name>-<ordinal index>`. Since the `web` StatefulSet has two
|
The Pods' names take the form `<statefulset name>-<ordinal index>`.
|
||||||
replicas, it creates two Pods, `web-0` and `web-1`.
|
Since the `web` StatefulSet has two 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/reference/generated/kubectl/kubectl-commands/#exec) to execute the
|
[`kubectl exec`](/docs/reference/generated/kubectl/kubectl-commands/#exec) to execute the
|
||||||
`hostname` command in each Pod.
|
`hostname` command in each Pod:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done
|
for i in 0 1; do kubectl exec "web-$i" -- sh -c 'hostname'; done
|
||||||
|
```
|
||||||
|
```
|
||||||
web-0
|
web-0
|
||||||
web-1
|
web-1
|
||||||
```
|
```
|
||||||
@@ -157,11 +172,18 @@ web-1
|
|||||||
Use [`kubectl run`](/docs/reference/generated/kubectl/kubectl-commands/#run) to execute
|
Use [`kubectl run`](/docs/reference/generated/kubectl/kubectl-commands/#run) to execute
|
||||||
a container that provides the `nslookup` command from the `dnsutils` package.
|
a container that provides the `nslookup` command from the `dnsutils` package.
|
||||||
Using `nslookup` on the Pods' hostnames, you can examine their in-cluster DNS
|
Using `nslookup` on the Pods' hostnames, you can examine their in-cluster DNS
|
||||||
addresses.
|
addresses:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm
|
kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm
|
||||||
|
```
|
||||||
|
which starts a new shell. In that new shell, run:
|
||||||
|
```shell
|
||||||
|
# Run this in the dns-test container shell
|
||||||
nslookup web-0.nginx
|
nslookup web-0.nginx
|
||||||
|
```
|
||||||
|
The output is similar to:
|
||||||
|
```
|
||||||
Server: 10.0.0.10
|
Server: 10.0.0.10
|
||||||
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
|
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
|
||||||
|
|
||||||
@@ -176,30 +198,36 @@ Name: web-1.nginx
|
|||||||
Address 1: 10.244.2.6
|
Address 1: 10.244.2.6
|
||||||
```
|
```
|
||||||
|
|
||||||
|
(and now exit the container shell: `exit`)
|
||||||
|
|
||||||
The CNAME of the headless service points to SRV records (one for each Pod that
|
The CNAME of the headless service points to SRV records (one for each Pod that
|
||||||
is Running and Ready). The SRV records point to A record entries that
|
is Running and Ready). The SRV records point to A record entries that
|
||||||
contain the Pods' IP addresses.
|
contain the Pods' IP addresses.
|
||||||
|
|
||||||
In one terminal, watch the StatefulSet's Pods.
|
In one terminal, watch the StatefulSet's Pods:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get pod -w -l app=nginx
|
kubectl get pod -w -l app=nginx
|
||||||
```
|
```
|
||||||
In a second terminal, use
|
In a second terminal, use
|
||||||
[`kubectl delete`](/docs/reference/generated/kubectl/kubectl-commands/#delete) to delete all
|
[`kubectl delete`](/docs/reference/generated/kubectl/kubectl-commands/#delete) to delete all
|
||||||
the Pods in the StatefulSet.
|
the Pods in the StatefulSet:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl delete pod -l app=nginx
|
kubectl delete pod -l app=nginx
|
||||||
|
```
|
||||||
|
```
|
||||||
pod "web-0" deleted
|
pod "web-0" deleted
|
||||||
pod "web-1" deleted
|
pod "web-1" deleted
|
||||||
```
|
```
|
||||||
|
|
||||||
Wait for the StatefulSet to restart them, and for both Pods to transition to
|
Wait for the StatefulSet to restart them, and for both Pods to transition to
|
||||||
Running and Ready.
|
Running and Ready:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get pod -w -l app=nginx
|
kubectl get pod -w -l app=nginx
|
||||||
|
```
|
||||||
|
```
|
||||||
NAME READY STATUS RESTARTS AGE
|
NAME READY STATUS RESTARTS AGE
|
||||||
web-0 0/1 ContainerCreating 0 0s
|
web-0 0/1 ContainerCreating 0 0s
|
||||||
NAME READY STATUS RESTARTS AGE
|
NAME READY STATUS RESTARTS AGE
|
||||||
@@ -210,16 +238,28 @@ web-1 0/1 ContainerCreating 0 0s
|
|||||||
web-1 1/1 Running 0 34s
|
web-1 1/1 Running 0 34s
|
||||||
```
|
```
|
||||||
|
|
||||||
Use `kubectl exec` and `kubectl run` to view the Pods hostnames and in-cluster
|
Use `kubectl exec` and `kubectl run` to view the Pods' hostnames and in-cluster
|
||||||
DNS entries.
|
DNS entries. First, view the Pods' hostnames:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done
|
for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done
|
||||||
|
```
|
||||||
|
```
|
||||||
web-0
|
web-0
|
||||||
web-1
|
web-1
|
||||||
|
```
|
||||||
|
then, run:
|
||||||
|
```
|
||||||
kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm /bin/sh
|
kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm /bin/sh
|
||||||
|
```
|
||||||
|
which starts a new shell.
|
||||||
|
In that new shell, run:
|
||||||
|
```shell
|
||||||
|
# Run this in the dns-test container shell
|
||||||
nslookup web-0.nginx
|
nslookup web-0.nginx
|
||||||
|
```
|
||||||
|
The output is similar to:
|
||||||
|
```
|
||||||
Server: 10.0.0.10
|
Server: 10.0.0.10
|
||||||
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
|
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
|
||||||
|
|
||||||
@@ -234,6 +274,8 @@ Name: web-1.nginx
|
|||||||
Address 1: 10.244.2.8
|
Address 1: 10.244.2.8
|
||||||
```
|
```
|
||||||
|
|
||||||
|
(and now exit the container shell: `exit`)
|
||||||
|
|
||||||
The Pods' ordinals, hostnames, SRV records, and A record names have not changed,
|
The Pods' ordinals, hostnames, SRV records, and A record names have not changed,
|
||||||
but the IP addresses associated with the Pods may have changed. In the cluster
|
but the IP addresses associated with the Pods may have changed. In the cluster
|
||||||
used for this tutorial, they have. This is why it is important not to configure
|
used for this tutorial, they have. This is why it is important not to configure
|
||||||
@@ -241,7 +283,7 @@ other applications to connect to Pods in a StatefulSet by IP address.
|
|||||||
|
|
||||||
|
|
||||||
If you need to find and connect to the active members of a StatefulSet, you
|
If you need to find and connect to the active members of a StatefulSet, you
|
||||||
should query the CNAME of the Headless Service
|
should query the CNAME of the headless Service
|
||||||
(`nginx.default.svc.cluster.local`). The SRV records associated with the
|
(`nginx.default.svc.cluster.local`). The SRV records associated with the
|
||||||
CNAME will contain only the Pods in the StatefulSet that are Running and
|
CNAME will contain only the Pods in the StatefulSet that are Running and
|
||||||
Ready.
|
Ready.
|
||||||
@@ -255,56 +297,67 @@ to Running and Ready.
|
|||||||
|
|
||||||
### Writing to Stable Storage
|
### Writing to Stable Storage
|
||||||
|
|
||||||
Get the PersistentVolumeClaims for `web-0` and `web-1`.
|
Get the PersistentVolumeClaims for `web-0` and `web-1`:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get pvc -l app=nginx
|
kubectl get pvc -l app=nginx
|
||||||
|
```
|
||||||
|
The output is similar to:
|
||||||
|
```
|
||||||
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
|
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
|
||||||
www-web-0 Bound pvc-15c268c7-b507-11e6-932f-42010a800002 1Gi RWO 48s
|
www-web-0 Bound pvc-15c268c7-b507-11e6-932f-42010a800002 1Gi RWO 48s
|
||||||
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
|
|
||||||
bound to two [PersistentVolumes](/docs/concepts/storage/persistent-volumes/). As the cluster used in this tutorial is configured to dynamically provision
|
|
||||||
PersistentVolumes, the PersistentVolumes were created and bound automatically.
|
|
||||||
|
|
||||||
The NGINX webservers, by default, will serve an index file at
|
The StatefulSet controller created two
|
||||||
|
{{< glossary_tooltip text="PersistentVolumeClaims" term_id="persistent-volume-claim" >}}
|
||||||
|
that are bound to two
|
||||||
|
{{< glossary_tooltip text="PersistentVolumes" term_id="persistent-volume" >}}.
|
||||||
|
|
||||||
|
As the cluster used in this tutorial is configured to dynamically provision PersistentVolumes,
|
||||||
|
the PersistentVolumes were created and bound automatically.
|
||||||
|
|
||||||
|
The NGINX webserver, by default, serves an index file from
|
||||||
`/usr/share/nginx/html/index.html`. The `volumeMounts` field in the
|
`/usr/share/nginx/html/index.html`. The `volumeMounts` field in the
|
||||||
StatefulSets `spec` ensures that the `/usr/share/nginx/html` directory is
|
StatefulSet's `spec` ensures that the `/usr/share/nginx/html` directory is
|
||||||
backed by a PersistentVolume.
|
backed by a PersistentVolume.
|
||||||
|
|
||||||
Write the Pods' hostnames to their `index.html` files and verify that the NGINX
|
Write the Pods' hostnames to their `index.html` files and verify that the NGINX
|
||||||
webservers serve the hostnames.
|
webservers serve the hostnames:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
for i in 0 1; do kubectl exec web-$i -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html'; done
|
for i in 0 1; do kubectl exec "web-$i" -- sh -c 'echo "$(hostname)" > /usr/share/nginx/html/index.html'; done
|
||||||
|
|
||||||
for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done
|
for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done
|
||||||
|
```
|
||||||
|
```
|
||||||
web-0
|
web-0
|
||||||
web-1
|
web-1
|
||||||
```
|
```
|
||||||
|
|
||||||
{{< note >}}
|
{{< note >}}
|
||||||
If you instead see 403 Forbidden responses for the above curl command,
|
If you instead see **403 Forbidden** responses for the above curl command,
|
||||||
you will need to fix the permissions of the directory mounted by the `volumeMounts`
|
you will need to fix the permissions of the directory mounted by the `volumeMounts`
|
||||||
(due to a [bug when using hostPath volumes](https://github.com/kubernetes/kubernetes/issues/2630)) with:
|
(due to a [bug when using hostPath volumes](https://github.com/kubernetes/kubernetes/issues/2630)),
|
||||||
|
by running:
|
||||||
|
|
||||||
```shell
|
`for i in 0 1; do kubectl exec web-$i -- chmod 755 /usr/share/nginx/html; done`
|
||||||
for i in 0 1; do kubectl exec web-$i -- chmod 755 /usr/share/nginx/html; done
|
|
||||||
```
|
|
||||||
|
|
||||||
before retrying the curl command above.
|
before retrying the `curl` command above.
|
||||||
{{< /note >}}
|
{{< /note >}}
|
||||||
|
|
||||||
In one terminal, watch the StatefulSet's Pods.
|
In one terminal, watch the StatefulSet's Pods:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get pod -w -l app=nginx
|
kubectl get pod -w -l app=nginx
|
||||||
```
|
```
|
||||||
|
|
||||||
In a second terminal, delete all of the StatefulSet's Pods.
|
In a second terminal, delete all of the StatefulSet's Pods:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl delete pod -l app=nginx
|
kubectl delete pod -l app=nginx
|
||||||
|
```
|
||||||
|
```
|
||||||
pod "web-0" deleted
|
pod "web-0" deleted
|
||||||
pod "web-1" deleted
|
pod "web-1" deleted
|
||||||
```
|
```
|
||||||
@@ -313,6 +366,8 @@ for all of the Pods to transition to Running and Ready.
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get pod -w -l app=nginx
|
kubectl get pod -w -l app=nginx
|
||||||
|
```
|
||||||
|
```
|
||||||
NAME READY STATUS RESTARTS AGE
|
NAME READY STATUS RESTARTS AGE
|
||||||
web-0 0/1 ContainerCreating 0 0s
|
web-0 0/1 ContainerCreating 0 0s
|
||||||
NAME READY STATUS RESTARTS AGE
|
NAME READY STATUS RESTARTS AGE
|
||||||
@@ -323,10 +378,12 @@ web-1 0/1 ContainerCreating 0 0s
|
|||||||
web-1 1/1 Running 0 34s
|
web-1 1/1 Running 0 34s
|
||||||
```
|
```
|
||||||
|
|
||||||
Verify the web servers continue to serve their hostnames.
|
Verify the web servers continue to serve their hostnames:
|
||||||
|
|
||||||
```
|
```
|
||||||
for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done
|
for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done
|
||||||
|
```
|
||||||
|
```
|
||||||
web-0
|
web-0
|
||||||
web-1
|
web-1
|
||||||
```
|
```
|
||||||
@@ -338,6 +395,7 @@ node `web-0`and `web-1` are scheduled on, their PersistentVolumes will be
|
|||||||
mounted to the 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.
|
||||||
This is accomplished by updating the `replicas` field. You can use either
|
This is accomplished by updating the `replicas` field. You can use either
|
||||||
[`kubectl scale`](/docs/reference/generated/kubectl/kubectl-commands/#scale) or
|
[`kubectl scale`](/docs/reference/generated/kubectl/kubectl-commands/#scale) or
|
||||||
@@ -345,17 +403,19 @@ This is accomplished by updating the `replicas` field. You can use either
|
|||||||
|
|
||||||
### Scaling Up
|
### Scaling Up
|
||||||
|
|
||||||
In one terminal window, watch the Pods in the StatefulSet.
|
In one terminal window, watch the Pods in the StatefulSet:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get pods -w -l app=nginx
|
kubectl get pods -w -l app=nginx
|
||||||
```
|
```
|
||||||
|
|
||||||
In another terminal window, use `kubectl scale` to scale the number of replicas
|
In another terminal window, use `kubectl scale` to scale the number of replicas
|
||||||
to 5.
|
to 5:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl scale sts web --replicas=5
|
kubectl scale sts web --replicas=5
|
||||||
|
```
|
||||||
|
```
|
||||||
statefulset.apps/web scaled
|
statefulset.apps/web scaled
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -364,6 +424,8 @@ for the three additional Pods to transition to Running and Ready.
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get pods -w -l app=nginx
|
kubectl get pods -w -l app=nginx
|
||||||
|
```
|
||||||
|
```
|
||||||
NAME READY STATUS RESTARTS AGE
|
NAME READY STATUS RESTARTS AGE
|
||||||
web-0 1/1 Running 0 2h
|
web-0 1/1 Running 0 2h
|
||||||
web-1 1/1 Running 0 2h
|
web-1 1/1 Running 0 2h
|
||||||
@@ -390,24 +452,28 @@ subsequent Pod.
|
|||||||
|
|
||||||
### Scaling Down
|
### Scaling Down
|
||||||
|
|
||||||
In one terminal, watch the StatefulSet's Pods.
|
In one terminal, watch the StatefulSet's Pods:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get pods -w -l app=nginx
|
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
|
||||||
three replicas.
|
three replicas:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl patch sts web -p '{"spec":{"replicas":3}}'
|
kubectl patch sts web -p '{"spec":{"replicas":3}}'
|
||||||
|
```
|
||||||
|
```
|
||||||
statefulset.apps/web patched
|
statefulset.apps/web patched
|
||||||
```
|
```
|
||||||
|
|
||||||
Wait for `web-4` and `web-3` to transition to Terminating.
|
Wait for `web-4` and `web-3` to transition to Terminating.
|
||||||
|
|
||||||
```
|
```shell
|
||||||
kubectl get pods -w -l app=nginx
|
kubectl get pods -w -l app=nginx
|
||||||
|
```
|
||||||
|
```
|
||||||
NAME READY STATUS RESTARTS AGE
|
NAME READY STATUS RESTARTS AGE
|
||||||
web-0 1/1 Running 0 3h
|
web-0 1/1 Running 0 3h
|
||||||
web-1 1/1 Running 0 3h
|
web-1 1/1 Running 0 3h
|
||||||
@@ -428,10 +494,12 @@ The controller deleted one Pod at a time, in reverse order with respect to its
|
|||||||
ordinal index, 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:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get pvc -l app=nginx
|
kubectl get pvc -l app=nginx
|
||||||
|
```
|
||||||
|
```
|
||||||
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
|
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
|
||||||
www-web-0 Bound pvc-15c268c7-b507-11e6-932f-42010a800002 1Gi RWO 13h
|
www-web-0 Bound pvc-15c268c7-b507-11e6-932f-42010a800002 1Gi RWO 13h
|
||||||
www-web-1 Bound pvc-15c79307-b507-11e6-932f-42010a800002 1Gi RWO 13h
|
www-web-1 Bound pvc-15c79307-b507-11e6-932f-42010a800002 1Gi RWO 13h
|
||||||
@@ -460,25 +528,32 @@ StatefulSet. There are two valid update strategies, `RollingUpdate` and
|
|||||||
The `RollingUpdate` update strategy will update all Pods in a StatefulSet, in
|
The `RollingUpdate` update strategy will update all Pods in a StatefulSet, in
|
||||||
reverse ordinal order, while respecting the StatefulSet guarantees.
|
reverse ordinal order, while respecting the StatefulSet guarantees.
|
||||||
|
|
||||||
Patch the `web` StatefulSet to apply the `RollingUpdate` update strategy.
|
Patch the `web` StatefulSet to apply the `RollingUpdate` update strategy:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate"}}}'
|
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate"}}}'
|
||||||
|
```
|
||||||
|
```
|
||||||
statefulset.apps/web patched
|
statefulset.apps/web patched
|
||||||
```
|
```
|
||||||
|
|
||||||
In one terminal window, patch the `web` StatefulSet to change the container
|
In one terminal window, patch the `web` StatefulSet to change the container
|
||||||
image again.
|
image again:
|
||||||
|
|
||||||
```shell
|
```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"}]'
|
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.apps/web patched
|
statefulset.apps/web patched
|
||||||
```
|
```
|
||||||
|
|
||||||
In another terminal, watch the Pods in the StatefulSet.
|
In another terminal, watch the Pods in the StatefulSet:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get po -l app=nginx -w
|
kubectl get pod -l app=nginx -w
|
||||||
|
```
|
||||||
|
The output is simular to:
|
||||||
|
```
|
||||||
NAME READY STATUS RESTARTS AGE
|
NAME READY STATUS RESTARTS AGE
|
||||||
web-0 1/1 Running 0 7m
|
web-0 1/1 Running 0 7m
|
||||||
web-1 1/1 Running 0 7m
|
web-1 1/1 Running 0 7m
|
||||||
@@ -518,16 +593,19 @@ StatefulSet controller terminates each Pod, and waits for it to transition to Ru
|
|||||||
Ready prior to updating the next Pod. Note that, even though the StatefulSet
|
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
|
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
|
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
|
its current version.
|
||||||
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.
|
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
|
```shell
|
||||||
for p in 0 1 2; do kubectl get po web-$p --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
|
for p in 0 1 2; do kubectl get pod "web-$p" --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
|
||||||
|
```
|
||||||
|
```
|
||||||
k8s.gcr.io/nginx-slim:0.8
|
k8s.gcr.io/nginx-slim:0.8
|
||||||
k8s.gcr.io/nginx-slim:0.8
|
k8s.gcr.io/nginx-slim:0.8
|
||||||
k8s.gcr.io/nginx-slim:0.8
|
k8s.gcr.io/nginx-slim:0.8
|
||||||
@@ -536,40 +614,51 @@ k8s.gcr.io/nginx-slim:0.8
|
|||||||
|
|
||||||
All the Pods in the StatefulSet are now running the previous container image.
|
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
|
{{< note >}}
|
||||||
the status of a rolling update.
|
You can also use `kubectl rollout status sts/<name>` to view
|
||||||
|
the status of a rolling update to a StatefulSet
|
||||||
|
{{< /note >}}
|
||||||
|
|
||||||
#### Staging an Update
|
#### Staging an Update
|
||||||
|
|
||||||
You can stage an update to a StatefulSet by using the `partition` parameter of
|
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
|
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
|
in the StatefulSet at the current version while allowing mutations to the
|
||||||
StatefulSet's `.spec.template`.
|
StatefulSet's `.spec.template`.
|
||||||
|
|
||||||
Patch the `web` StatefulSet to add a partition to the `updateStrategy` field.
|
Patch the `web` StatefulSet to add a partition to the `updateStrategy` field:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}'
|
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}'
|
||||||
|
```
|
||||||
|
```
|
||||||
statefulset.apps/web patched
|
statefulset.apps/web patched
|
||||||
```
|
```
|
||||||
|
|
||||||
Patch the StatefulSet again to change the container's image.
|
Patch the StatefulSet again to change the container's image:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"k8s.gcr.io/nginx-slim:0.7"}]'
|
kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"k8s.gcr.io/nginx-slim:0.7"}]'
|
||||||
|
```
|
||||||
|
```
|
||||||
statefulset.apps/web patched
|
statefulset.apps/web patched
|
||||||
```
|
```
|
||||||
|
|
||||||
Delete a Pod in the StatefulSet.
|
Delete a Pod in the StatefulSet:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl delete po web-2
|
kubectl delete pod web-2
|
||||||
|
```
|
||||||
|
```
|
||||||
pod "web-2" deleted
|
pod "web-2" deleted
|
||||||
```
|
```
|
||||||
|
|
||||||
Wait for the Pod to be Running and Ready.
|
Wait for the Pod to be Running and Ready.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get po -l app=nginx -w
|
kubectl get pod -l app=nginx -w
|
||||||
|
```
|
||||||
|
```
|
||||||
NAME READY STATUS RESTARTS AGE
|
NAME READY STATUS RESTARTS AGE
|
||||||
web-0 1/1 Running 0 4m
|
web-0 1/1 Running 0 4m
|
||||||
web-1 1/1 Running 0 4m
|
web-1 1/1 Running 0 4m
|
||||||
@@ -577,34 +666,40 @@ web-2 0/1 ContainerCreating 0 11s
|
|||||||
web-2 1/1 Running 0 18s
|
web-2 1/1 Running 0 18s
|
||||||
```
|
```
|
||||||
|
|
||||||
Get the Pod's container.
|
Get the Pod's container image:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get po web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
|
kubectl get pod web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
|
||||||
|
```
|
||||||
|
```
|
||||||
k8s.gcr.io/nginx-slim:0.8
|
k8s.gcr.io/nginx-slim:0.8
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Notice that, even though the update strategy is `RollingUpdate` the StatefulSet
|
Notice that, even though the update strategy is `RollingUpdate` the StatefulSet
|
||||||
controller restored the Pod with its original container. This is because the
|
restored the Pod with its original container. This is because the
|
||||||
ordinal of the Pod is less than the `partition` specified by the
|
ordinal of the Pod is less than the `partition` specified by the
|
||||||
`updateStrategy`.
|
`updateStrategy`.
|
||||||
|
|
||||||
#### Rolling Out a Canary
|
#### Rolling Out a Canary
|
||||||
|
|
||||||
You can roll out a canary to test a modification by decrementing the `partition`
|
You can roll out a canary to test a modification by decrementing the `partition`
|
||||||
you specified [above](#staging-an-update).
|
you specified [above](#staging-an-update).
|
||||||
|
|
||||||
Patch the StatefulSet to decrement the partition.
|
Patch the StatefulSet to decrement the partition:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":2}}}}'
|
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":2}}}}'
|
||||||
|
```
|
||||||
|
```
|
||||||
statefulset.apps/web patched
|
statefulset.apps/web patched
|
||||||
```
|
```
|
||||||
|
|
||||||
Wait for `web-2` to be Running and Ready.
|
Wait for `web-2` to be Running and Ready.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get po -l app=nginx -w
|
kubectl get pod -l app=nginx -w
|
||||||
|
```
|
||||||
|
```
|
||||||
NAME READY STATUS RESTARTS AGE
|
NAME READY STATUS RESTARTS AGE
|
||||||
web-0 1/1 Running 0 4m
|
web-0 1/1 Running 0 4m
|
||||||
web-1 1/1 Running 0 4m
|
web-1 1/1 Running 0 4m
|
||||||
@@ -612,10 +707,12 @@ web-2 0/1 ContainerCreating 0 11s
|
|||||||
web-2 1/1 Running 0 18s
|
web-2 1/1 Running 0 18s
|
||||||
```
|
```
|
||||||
|
|
||||||
Get the Pod's container.
|
Get the Pod's container:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get po web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
|
kubectl get pod web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
|
||||||
|
```
|
||||||
|
```
|
||||||
k8s.gcr.io/nginx-slim:0.7
|
k8s.gcr.io/nginx-slim:0.7
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -624,17 +721,22 @@ When you changed the `partition`, the StatefulSet controller automatically
|
|||||||
updated the `web-2` Pod because the Pod's ordinal was greater than or equal to
|
updated the `web-2` Pod because the Pod's ordinal was greater than or equal to
|
||||||
the `partition`.
|
the `partition`.
|
||||||
|
|
||||||
Delete the `web-1` Pod.
|
Delete the `web-1` Pod:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl delete po web-1
|
kubectl delete pod web-1
|
||||||
|
```
|
||||||
|
```
|
||||||
pod "web-1" deleted
|
pod "web-1" deleted
|
||||||
```
|
```
|
||||||
|
|
||||||
Wait for the `web-1` Pod to be Running and Ready.
|
Wait for the `web-1` Pod to be Running and Ready.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get po -l app=nginx -w
|
kubectl get pod -l app=nginx -w
|
||||||
|
```
|
||||||
|
The output is similar to:
|
||||||
|
```
|
||||||
NAME READY STATUS RESTARTS AGE
|
NAME READY STATUS RESTARTS AGE
|
||||||
web-0 1/1 Running 0 6m
|
web-0 1/1 Running 0 6m
|
||||||
web-1 0/1 Terminating 0 6m
|
web-1 0/1 Terminating 0 6m
|
||||||
@@ -648,13 +750,15 @@ web-1 0/1 ContainerCreating 0 0s
|
|||||||
web-1 1/1 Running 0 18s
|
web-1 1/1 Running 0 18s
|
||||||
```
|
```
|
||||||
|
|
||||||
Get the `web-1` Pods container.
|
Get the `web-1` Pod's container image:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get po web-1 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
|
kubectl get pod web-1 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
|
||||||
k8s.gcr.io/nginx-slim:0.8
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
```
|
||||||
|
k8s.gcr.io/nginx-slim:0.8
|
||||||
|
```
|
||||||
|
|
||||||
`web-1` was restored to its original configuration because the Pod's ordinal
|
`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
|
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
|
ordinal that is greater than or equal to the partition will be updated when the
|
||||||
@@ -663,23 +767,29 @@ than the partition is deleted or otherwise terminated, it will be restored to
|
|||||||
its original configuration.
|
its original configuration.
|
||||||
|
|
||||||
#### Phased Roll Outs
|
#### Phased Roll Outs
|
||||||
|
|
||||||
You can perform a phased roll out (e.g. a linear, geometric, or exponential
|
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
|
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
|
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
|
the `partition` to the ordinal at which you want the controller to pause the
|
||||||
update.
|
update.
|
||||||
|
|
||||||
The partition is currently set to `2`. Set the partition to `0`.
|
The partition is currently set to `2`. Set the partition to `0`:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":0}}}}'
|
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":0}}}}'
|
||||||
|
```
|
||||||
|
```
|
||||||
statefulset.apps/web patched
|
statefulset.apps/web patched
|
||||||
```
|
```
|
||||||
|
|
||||||
Wait for all of the Pods in the StatefulSet to become Running and Ready.
|
Wait for all of the Pods in the StatefulSet to become Running and Ready.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get po -l app=nginx -w
|
kubectl get pod -l app=nginx -w
|
||||||
|
```
|
||||||
|
The output is similar to:
|
||||||
|
```
|
||||||
NAME READY STATUS RESTARTS AGE
|
NAME READY STATUS RESTARTS AGE
|
||||||
web-0 1/1 Running 0 3m
|
web-0 1/1 Running 0 3m
|
||||||
web-1 0/1 ContainerCreating 0 11s
|
web-1 0/1 ContainerCreating 0 11s
|
||||||
@@ -697,17 +807,18 @@ web-0 0/1 ContainerCreating 0 0s
|
|||||||
web-0 1/1 Running 0 3s
|
web-0 1/1 Running 0 3s
|
||||||
```
|
```
|
||||||
|
|
||||||
Get the Pod's containers.
|
Get the container image details for the Pods in the StatefulSet:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
for p in 0 1 2; do kubectl get po web-$p --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
|
for p in 0 1 2; do kubectl get pod "web-$p" --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
|
||||||
|
```
|
||||||
|
```
|
||||||
k8s.gcr.io/nginx-slim:0.7
|
k8s.gcr.io/nginx-slim:0.7
|
||||||
k8s.gcr.io/nginx-slim:0.7
|
k8s.gcr.io/nginx-slim:0.7
|
||||||
k8s.gcr.io/nginx-slim:0.7
|
k8s.gcr.io/nginx-slim:0.7
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
By moving the `partition` to `0`, you allowed the StatefulSet controller to
|
By moving the `partition` to `0`, you allowed the StatefulSet to
|
||||||
continue the update process.
|
continue the update process.
|
||||||
|
|
||||||
### On Delete
|
### On Delete
|
||||||
@@ -740,13 +851,17 @@ not delete any of its Pods.
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl delete statefulset web --cascade=false
|
kubectl delete statefulset web --cascade=false
|
||||||
|
```
|
||||||
|
```
|
||||||
statefulset.apps "web" deleted
|
statefulset.apps "web" deleted
|
||||||
```
|
```
|
||||||
|
|
||||||
Get the Pods to examine their status.
|
Get the Pods, to examine their status:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get pods -l app=nginx
|
kubectl get pods -l app=nginx
|
||||||
|
```
|
||||||
|
```
|
||||||
NAME READY STATUS RESTARTS AGE
|
NAME READY STATUS RESTARTS AGE
|
||||||
web-0 1/1 Running 0 6m
|
web-0 1/1 Running 0 6m
|
||||||
web-1 1/1 Running 0 7m
|
web-1 1/1 Running 0 7m
|
||||||
@@ -754,17 +869,21 @@ web-2 1/1 Running 0 5m
|
|||||||
```
|
```
|
||||||
|
|
||||||
Even though `web` has been deleted, all of the Pods are still Running and Ready.
|
Even though `web` has been deleted, all of the Pods are still Running and Ready.
|
||||||
Delete `web-0`.
|
Delete `web-0`:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl delete pod web-0
|
kubectl delete pod web-0
|
||||||
|
```
|
||||||
|
```
|
||||||
pod "web-0" deleted
|
pod "web-0" deleted
|
||||||
```
|
```
|
||||||
|
|
||||||
Get the StatefulSet's Pods.
|
Get the StatefulSet's Pods:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get pods -l app=nginx
|
kubectl get pods -l app=nginx
|
||||||
|
```
|
||||||
|
```
|
||||||
NAME READY STATUS RESTARTS AGE
|
NAME READY STATUS RESTARTS AGE
|
||||||
web-1 1/1 Running 0 10m
|
web-1 1/1 Running 0 10m
|
||||||
web-2 1/1 Running 0 7m
|
web-2 1/1 Running 0 7m
|
||||||
@@ -779,22 +898,26 @@ kubectl get pods -w -l app=nginx
|
|||||||
```
|
```
|
||||||
|
|
||||||
In a second terminal, recreate the StatefulSet. Note that, unless
|
In a second terminal, recreate the StatefulSet. Note that, unless
|
||||||
you deleted the `nginx` Service ( which you should not have ), you will see
|
you deleted the `nginx` Service (which you should not have), you will see
|
||||||
an error indicating that the Service already exists.
|
an error indicating that the Service already exists.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl apply -f web.yaml
|
kubectl apply -f web.yaml
|
||||||
|
```
|
||||||
|
```
|
||||||
statefulset.apps/web created
|
statefulset.apps/web created
|
||||||
service/nginx unchanged
|
service/nginx unchanged
|
||||||
```
|
```
|
||||||
|
|
||||||
Ignore the error. It only indicates that an attempt was made to create the nginx
|
Ignore the error. It only indicates that an attempt was made to create the _nginx_
|
||||||
Headless Service even though that Service already exists.
|
headless Service even though that Service already exists.
|
||||||
|
|
||||||
Examine the output of the `kubectl get` command running in the first terminal.
|
Examine the output of the `kubectl get` command running in the first terminal.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get pods -w -l app=nginx
|
kubectl get pods -w -l app=nginx
|
||||||
|
```
|
||||||
|
```
|
||||||
NAME READY STATUS RESTARTS AGE
|
NAME READY STATUS RESTARTS AGE
|
||||||
web-1 1/1 Running 0 16m
|
web-1 1/1 Running 0 16m
|
||||||
web-2 1/1 Running 0 2m
|
web-2 1/1 Running 0 2m
|
||||||
@@ -817,10 +940,12 @@ Since `web-1` was already Running and Ready, when `web-0` transitioned to
|
|||||||
terminated.
|
terminated.
|
||||||
|
|
||||||
Let's take another look at the contents of the `index.html` file served by the
|
Let's take another look at the contents of the `index.html` file served by the
|
||||||
Pods' webservers.
|
Pods' webservers:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done
|
for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done
|
||||||
|
```
|
||||||
|
```
|
||||||
web-0
|
web-0
|
||||||
web-1
|
web-1
|
||||||
```
|
```
|
||||||
@@ -844,6 +969,8 @@ In another terminal, delete the StatefulSet again. This time, omit the
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl delete statefulset web
|
kubectl delete statefulset web
|
||||||
|
```
|
||||||
|
```
|
||||||
statefulset.apps "web" deleted
|
statefulset.apps "web" deleted
|
||||||
```
|
```
|
||||||
Examine the output of the `kubectl get` command running in the first terminal,
|
Examine the output of the `kubectl get` command running in the first terminal,
|
||||||
@@ -851,6 +978,8 @@ and wait for all of the Pods to transition to Terminating.
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get pods -w -l app=nginx
|
kubectl get pods -w -l app=nginx
|
||||||
|
```
|
||||||
|
```
|
||||||
NAME READY STATUS RESTARTS AGE
|
NAME READY STATUS RESTARTS AGE
|
||||||
web-0 1/1 Running 0 11m
|
web-0 1/1 Running 0 11m
|
||||||
web-1 1/1 Running 0 27m
|
web-1 1/1 Running 0 27m
|
||||||
@@ -871,43 +1000,58 @@ are terminated one at a time, with respect to the reverse order of their ordinal
|
|||||||
indices. Before terminating a Pod, the StatefulSet controller waits for
|
indices. Before terminating a Pod, the StatefulSet controller waits for
|
||||||
the Pod's successor to be completely terminated.
|
the Pod's successor to be completely terminated.
|
||||||
|
|
||||||
Note that, while a cascading delete will delete the StatefulSet and its Pods,
|
{{< note >}}
|
||||||
it will not delete the Headless Service associated with the StatefulSet. You
|
Although a cascading delete removes a StatefulSet together with its Pods,
|
||||||
must delete the `nginx` Service manually.
|
the cascade does not delete the headless Service associated with the StatefulSet.
|
||||||
|
You must delete the `nginx` Service manually.
|
||||||
|
{{< /note >}}
|
||||||
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl delete service nginx
|
kubectl delete service nginx
|
||||||
|
```
|
||||||
|
```
|
||||||
service "nginx" deleted
|
service "nginx" deleted
|
||||||
```
|
```
|
||||||
|
|
||||||
Recreate the StatefulSet and Headless Service one more time.
|
Recreate the StatefulSet and headless Service one more time:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl apply -f web.yaml
|
kubectl apply -f web.yaml
|
||||||
|
```
|
||||||
|
```
|
||||||
service/nginx created
|
service/nginx created
|
||||||
statefulset.apps/web created
|
statefulset.apps/web created
|
||||||
```
|
```
|
||||||
|
|
||||||
When all of the StatefulSet's Pods transition to Running and Ready, retrieve
|
When all of the StatefulSet's Pods transition to Running and Ready, retrieve
|
||||||
the contents of their `index.html` files.
|
the contents of their `index.html` files:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done
|
for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done
|
||||||
|
```
|
||||||
|
```
|
||||||
web-0
|
web-0
|
||||||
web-1
|
web-1
|
||||||
```
|
```
|
||||||
|
|
||||||
Even though you completely deleted the StatefulSet, and all of its Pods, the
|
Even though you completely deleted the StatefulSet, and all of its Pods, the
|
||||||
Pods are recreated with their PersistentVolumes mounted, and `web-0` and
|
Pods are recreated with their PersistentVolumes mounted, and `web-0` and
|
||||||
`web-1` will still serve their hostnames.
|
`web-1` continue to serve their hostnames.
|
||||||
|
|
||||||
Finally delete the `web` StatefulSet and the `nginx` service.
|
Finally, delete the `web` StatefulSet...
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl delete service nginx
|
kubectl delete service nginx
|
||||||
|
```
|
||||||
|
```
|
||||||
service "nginx" deleted
|
service "nginx" deleted
|
||||||
|
```
|
||||||
|
...and the `nginx` Service:
|
||||||
|
```shell
|
||||||
kubectl delete statefulset web
|
kubectl delete statefulset web
|
||||||
|
```
|
||||||
|
```
|
||||||
statefulset "web" deleted
|
statefulset "web" deleted
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -941,13 +1085,15 @@ of the `web` StatefulSet is set to `Parallel`.
|
|||||||
In one terminal, watch the Pods in the StatefulSet.
|
In one terminal, watch the Pods in the StatefulSet.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get po -l app=nginx -w
|
kubectl get pod -l app=nginx -w
|
||||||
```
|
```
|
||||||
|
|
||||||
In another terminal, create the StatefulSet and Service in the manifest.
|
In another terminal, create the StatefulSet and Service in the manifest:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl apply -f web-parallel.yaml
|
kubectl apply -f web-parallel.yaml
|
||||||
|
```
|
||||||
|
```
|
||||||
service/nginx created
|
service/nginx created
|
||||||
statefulset.apps/web created
|
statefulset.apps/web created
|
||||||
```
|
```
|
||||||
@@ -955,7 +1101,9 @@ statefulset.apps/web created
|
|||||||
Examine the output of the `kubectl get` command that you executed in the first terminal.
|
Examine the output of the `kubectl get` command that you executed in the first terminal.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl get po -l app=nginx -w
|
kubectl get pod -l app=nginx -w
|
||||||
|
```
|
||||||
|
```
|
||||||
NAME READY STATUS RESTARTS AGE
|
NAME READY STATUS RESTARTS AGE
|
||||||
web-0 0/1 Pending 0 0s
|
web-0 0/1 Pending 0 0s
|
||||||
web-0 0/1 Pending 0 0s
|
web-0 0/1 Pending 0 0s
|
||||||
@@ -970,16 +1118,18 @@ web-1 1/1 Running 0 10s
|
|||||||
The StatefulSet controller launched both `web-0` and `web-1` at the same time.
|
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
|
Keep the second terminal open, and, in another terminal window scale the
|
||||||
StatefulSet.
|
StatefulSet:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl scale statefulset/web --replicas=4
|
kubectl scale statefulset/web --replicas=4
|
||||||
|
```
|
||||||
|
```
|
||||||
statefulset.apps/web scaled
|
statefulset.apps/web scaled
|
||||||
```
|
```
|
||||||
|
|
||||||
Examine the output of the terminal where the `kubectl get` command is running.
|
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 0s
|
web-3 0/1 Pending 0 0s
|
||||||
web-3 0/1 Pending 0 7s
|
web-3 0/1 Pending 0 7s
|
||||||
@@ -989,18 +1139,24 @@ web-3 1/1 Running 0 26s
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
The StatefulSet controller launched two new Pods, and it did not wait for
|
The StatefulSet launched two new Pods, and it did not wait for
|
||||||
the first to become Running and Ready prior to launching the second.
|
the first to become Running and Ready prior to launching the second.
|
||||||
|
|
||||||
Keep this terminal open, and in another terminal delete the `web` StatefulSet.
|
## {{% heading "cleanup" %}}
|
||||||
|
|
||||||
|
You should have two terminals open, ready for you to run `kubectl` commands as
|
||||||
|
part of cleanup.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl delete sts web
|
kubectl delete sts web
|
||||||
|
# sts is an abbreviation for statefulset
|
||||||
```
|
```
|
||||||
|
|
||||||
Again, examine the output of the `kubectl get` command running in the other terminal.
|
You can watch `kubectl get` to see those Pods being deleted.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
kubectl get pod -l app=nginx -w
|
||||||
|
```
|
||||||
|
```
|
||||||
web-3 1/1 Terminating 0 9m
|
web-3 1/1 Terminating 0 9m
|
||||||
web-2 1/1 Terminating 0 9m
|
web-2 1/1 Terminating 0 9m
|
||||||
web-3 1/1 Terminating 0 9m
|
web-3 1/1 Terminating 0 9m
|
||||||
@@ -1026,20 +1182,22 @@ 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
|
During deletion, a StatefulSet removes all Pods concurrently; it does not wait for
|
||||||
a Pod's ordinal successor to terminate prior to deleting that Pod.
|
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`
|
Close the terminal where the `kubectl get` command is running and delete the `nginx`
|
||||||
Service.
|
Service:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl delete svc nginx
|
kubectl delete svc nginx
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## {{% heading "cleanup" %}}
|
{{< note >}}
|
||||||
|
You also need to delete the persistent storage media for the PersistentVolumes
|
||||||
|
used in this tutorial.
|
||||||
|
|
||||||
You will need to delete the persistent storage media for the PersistentVolumes
|
|
||||||
used in this tutorial. Follow the necessary steps, based on your environment,
|
Follow the necessary steps, based on your environment, storage configuration,
|
||||||
storage configuration, and provisioning method, to ensure that all storage is
|
and provisioning method, to ensure that all storage is reclaimed.
|
||||||
reclaimed.
|
{{< /note >}}
|
||||||
|
|||||||
Reference in New Issue
Block a user