# StatefulSet 更新策略

StatefulSet 和 Deployment 一样，也提供了多种更新策略，可以在 <mark style="color:blue;">**.spec.updateStrategy**</mark> 字段中指定StatefulSet 的更新策略。

* <mark style="color:blue;">**OnDelete 策略**</mark>
  * OnDelete 更新策略实现了传统的更新行为。
  * 当选择这个更新策略并修改 StatefulSet 的 **.spec.template** 字段时，<mark style="color:blue;">**StatefulSet 控制器不会自动更新 Pod，必须手动删除 Pod 才能使控制器创建新的 Pod**</mark>。
* <mark style="color:blue;">**RollingUpdate 策略（默认策略）**</mark>
  * RollingUpdate（滚动更新）策略会<mark style="color:blue;">**自动更新一个 StatefulSet 中所有的 Pod，采用与序号索引相反的顺序进行滚动更新**</mark>。

## 滚动更新示例

```properties
$ kubectl set image sts web nginx=nginx:1.25.3
statefulset.apps/web image updated
```

如上所述，StatefulSet 中的 Pod 采用和序号相反的顺序更新。

* 在更新下一个 Pod 前，StatefulSet 控制器会终止每一个 Pod 并等待它们变成 Running 和 Ready 状态。
* 在当前顺序变成 Running 和 Ready 状态之前，StatefulSet 控制器不会更新下一个 Pod，但它仍然会重建任何在更新过程中发生故障的 Pod，使用它们当前的版本。
* 已经接收到请求的 Pod 将会被恢复为更新的版本，没有收到请求的 Pod 则会被恢复为之前的版本。

<pre class="language-properties"><code class="lang-properties"><strong>$ kubectl get pod -w -l app=nginx
</strong>NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          3m21s
web-1   1/1     Running   0          3m19s
web-1   1/1     Terminating   0          3m52s
web-1   1/1     Terminating   0          3m52s
web-1   0/1     Terminating   0          3m52s
web-1   0/1     Terminating   0          3m53s
web-1   0/1     Terminating   0          3m53s
web-1   0/1     Terminating   0          3m53s
web-1   0/1     Pending       0          0s
web-1   0/1     Pending       0          0s
web-1   0/1     ContainerCreating   0          0s
web-1   0/1     ContainerCreating   0          1s
web-1   1/1     Running             0          2s
web-0   1/1     Terminating         0          3m57s
web-0   1/1     Terminating         0          3m58s
web-0   0/1     Terminating         0          3m58s
web-0   0/1     Terminating         0          3m58s
web-0   0/1     Terminating         0          3m58s
web-0   0/1     Terminating         0          3m58s
web-0   0/1     Pending             0          0s
web-0   0/1     Pending             0          0s
web-0   0/1     ContainerCreating   0          0s
web-0   0/1     ContainerCreating   0          1s
web-0   1/1     Running             0          2s
</code></pre>

获取 Pod 来查看它们的容器镜像：

{% code overflow="wrap" %}

```shell
$ for p in 0 1; do kubectl get pod "web-$p" --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
nginx:1.25.3
nginx:1.25.3
```

{% endcode %}

## 分段更新

可以使用 <mark style="color:blue;">**RollingUpdate 更新策略的 partition 参数**</mark>来分段更新一个 StatefulSet。

**分段更新**将会<mark style="color:blue;">**只更新序号大于等于分区的 Pod**</mark><mark style="color:blue;">，</mark><mark style="color:blue;">**其余的所有 Pod（序号小于分区）保持当前版本**</mark>，利用此特性可以简单实现金丝雀发布（灰度发布）或者分阶段推出新功能等。

比如我们定义一个**分区"partition":3**，可以使用 **patch** 或 **edit** 直接对 StatefulSet 进行设置：

{% code overflow="wrap" %}

```properties
$ kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}'
```

{% endcode %}

使用 **patch** 改变容器的镜像：

{% code overflow="wrap" %}

```properties
$ kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"registry.k8s.io/nginx-slim:0.7"}]'
```

{% endcode %}

> ## 测试小于分区的Pod将保持当前版本
>
> <mark style="color:orange;">**删除Pod触发更新：**</mark>
>
> ```properties
> $ kubectl delete pod web-2
> pod "web-2" deleted
> ```
>
> <mark style="color:orange;">**此时，因为 Pod web-2 的序号小于分区 3，所以 Pod 不会被更新，还是会使用以前的容器恢复 Pod。**</mark>
>
> {% code overflow="wrap" %}
>
> ```properties
> $ kubectl get pod web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
> nginx:1.25.3
> ```
>
> {% endcode %}

> ## **测试序号大于等于分区的Pod会被更新**
>
> **将分区改为 2**，此时会自动更新 web-2，但是不会更新 web-0 和 web-1：
>
> {% code overflow="wrap" %}
>
> ```properties
> kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":2}}}}'
> ```
>
> {% endcode %}
>
> ```properties
> kubectl get pod web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
> registry.k8s.io/nginx-slim:0.7
> ```
