方法1:滚动重启

从 1.15 版开始,Kubernetes 允许滚动重启 Deployment,这是最快的重启方式:

1
kubectl rollout restart deployment [deployment_name]

该命令会逐步关闭并重启 Deployment 中的每个 Pod 容器,重启过程中应用仍然可用,因为大多数容器仍在运行。

方法2:使用环境变量

通过设置或更改环境变量,可以强制 Pod 重新启动并同步变更。例如,更改容器部署日期:

1
kubectl set env deployment [deployment_name] DEPLOY_DATE="$(date)"

方法3:缩放副本数

使用 scale 命令将副本数设置为 0 来关闭容器:

1
kubectl scale deployment [deployment_name] --replicas=0

再将副本数恢复为大于零的值来重新启动:

1
kubectl scale deployment [deployment_name] --replicas=1

Kubernetes 会销毁旧副本并创建新副本,新副本的名称会与旧副本不同。可以使用 kubectl get pods 查看状态和新名称。

上面通过 kubectl rollout restart 重新启动,Deployment 会创建新的副本并等待它们启动,然后删除旧 Pod 并重新路由流量,服务不会中断。接下来介绍如何使用 CronJob 配合 rollout restart 定时重启 Pod。

方法4:使用cronjob命令配合rollout restart每天定时重启动pod

在开始之前必须先设置RBAC,以便从集群内部运行的Kubernetes client具有对Kubernetes API执行所需调用的权限。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#Service account the client will use to reset the deployment,
#by default the pods running inside the cluster can do no such things.
kind: ServiceAccount
apiVersion: v1
metadata:
name: deployment-restart
namespace: <YOUR NAMESPACE>
---
# allow getting status and patching only the one deployment you want
# to restart
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: deployment-restart
namespace: <YOUR NAMESPACE>
rules:
# if you wanna watch pod resources,add "metrics.k8s.io"
- apiGroups: ["", "apps", "extensions", "metrics.k8s.io"]
# if you wanna execute pod,add "pod/exec"
resources: ["deployments", "pods", "pods/exec"]
# ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed.
resourceNames: ["<YOUR DEPLOYMENT NAME>"]
verbs: ["get", "patch", "list", "watch"] # "list" and "watch" are only needed
# if you want to use `rollout status`
---
# bind the role to the service account
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: deployment-restart
namespace: <YOUR NAMESPACE>
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: deployment-restart
subjects:
- kind: ServiceAccount
name: deployment-restart
namespace: <YOUR NAMESPACE>
---
# cronjob配置:
apiVersion: batch/v1
kind: CronJob
metadata:
name: deployment-restart
namespace: <YOUR NAMESPACE>
spec:
concurrencyPolicy: Forbid
schedule: '0 8 * * *' # cron spec of time, here, 8 o'clock
jobTemplate:
spec:
backoffLimit: 2 # this has very low chance of failing, as all this does
# is prompt kubernetes to schedule new replica set for
# the deployment
activeDeadlineSeconds: 600 # timeout, makes most sense with
# "waiting for rollout" variant specified below
template:
spec:
serviceAccountName: deployment-restart # name of the service
# account configured above
restartPolicy: Never
containers:
- name: kubectl
image: bitnami/kubectl # probably any kubectl image will do,
# optionaly specify version, but this
# should not be necessary, as long the
# version of kubectl is new enough to
# have `rollout restart`
command:
- 'kubectl'
- 'rollout'
- 'restart'
- 'deployment/<YOUR DEPLOYMENT NAME>'

如果希望cronjob等待部署完成,可以将cronjob命令更改为:

1
2
3
4
5
6
command:
- bash
- -c
- |-
kubectl rollout restart deployment/<YOUR DEPLOYMENT NAME> &&
kubectl rollout status deployment/<YOUR DEPLOYMENT NAME>

以下是一个判断对应服务内存是否超过 1500Mi 并自动重启的示例:

1
2
3
4
5
6
7
8
9
10
11
command:
- bash
- '-c'
- |-
MAX_RESOURCE=1500
NAME_SPACE=?;
DEPLOY_NAME=?;
if [[ $(kubectl top pods -n $NAME_SPACE --selector app=$DEPLOY_NAME | awk 'NR>1 {mem=$3; sub(/Mi/, "", mem); if (mem > $MAX_RESOURCE) {over=1}} END {if (over) {print "WARN"}}') == 'WARN' ]] ; then
echo "WARN: memory usage over $MAX_RESOURCE"
kubectl rollout restart deployment -n $NAME_SPACE $DEPLOY_NAME
fi

补充一个定期删除某 Deployment 下以 upload 开头的文件的指令:

1
2
3
4
5
6
7
8
9
command:
- bash
- '-c'
- |-
NAME_SPACE=?;
DEPLOY_NAME=?;
for pod in $(kubectl get pod -n $NAME_SPACE --selector "app=$DEPLOY_NAME" -o jsonpath='{.items[*].metadata.name}'); do
kubectl exec $pod -n $NAME_SPACE -- find /tmp -mtime +1 -name 'upload_*' -type f -print -exec rm -f {} \;
done