Kubernetes - 滚动更新杀死旧的pod而不启动新的pod

19

我目前正在使用Deployments来管理K8S集群中的Pod。

我的一些Deployment需要2个Pod/副本,有些需要3个Pod/副本,而有些只需要1个Pod/副本。我遇到的问题是只有一个Pod/副本的情况。

我的YAML文件如下:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: user-management-backend-deployment
spec:
  replicas: 1
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 2
  selector:
    matchLabels:
      name: user-management-backend
  template:
    metadata:
      labels:
        name: user-management-backend
    spec:
      containers:
      - name: user-management-backend
        image: proj_csdp/user-management_backend:3.1.8
        imagePullPolicy: IfNotPresent
        ports:
          - containerPort: 8080
        livenessProbe:
          httpGet:
            port: 8080
            path: /user_management/health
          initialDelaySeconds: 300
          timeoutSeconds: 30
        readinessProbe:
          httpGet:
            port: 8080
            path: /user_management/health
          initialDelaySeconds: 10
          timeoutSeconds: 5
        volumeMounts:
          - name: nfs
            mountPath: "/vault"
      volumes:
        - name: nfs
          nfs:
            server: kube-nfs
            path: "/kubenfs/vault"
            readOnly: true

我有一个旧版本可以运行良好。

# kubectl get po | grep  user-management-backend-deployment
user-management-backend-deployment-3264073543-mrrvl               1/1       Running        0          4d

现在我想要更新这张图片:

# kubectl set image deployment  user-management-backend-deployment  user-management-backend=proj_csdp/user-management_backend:3.2.0

根据RollingUpdate的设计,K8S应该在保持旧Pod正常工作的同时启动新Pod,只有当新Pod准备好接收流量时,才会删除旧Pod。但是我发现旧Pod立即被删除,然后创建新Pod并且需要一些时间才能开始接收流量,这意味着我必须放弃流量。

# kubectl get po | grep  user-management-backend-deployment
user-management-backend-deployment-3264073543-l93m9               0/1       ContainerCreating   0          1s

# kubectl get po | grep  user-management-backend-deployment
user-management-backend-deployment-3264073543-l93m9               1/1       Running            0          33s

我已经使用了maxSurge: 2maxUnavailable: 1,但似乎并没有起作用。

你有任何想法为什么会这样吗?

4个回答

30

看起来是 maxUnavailable: 1 的问题;我可以轻松地重现您设置该值的经历,并通过将其设置为 maxUnavailable: 0 轻松地实现正确的经历。

以下是调度器如何产生您正在经历的行为的“伪证明”:

由于 replicas: 1,k8s 的期望状态恰好是一种处于 Ready 状态的 Pod。在滚动更新操作期间(这是您请求的策略),它将创建一个新的 Pod,使总数达到 2。但是,您允许 k8s 将 一个 Pod 保持不可用状态,并指示它保持 期望的 1 个 Pod 数量。因此,它满足了所有这些约束条件:1 个 Pod,在不可用状态下,符合 R-U 策略所允许的期望计数。

通过将 maxUnavailable 设置为零,您正确地指示 k8s 永远不要让任何 Pod 不可用,即使这意味着在短时间内将 Pods 飙升到超过 replica 计数。


假设我们有这个部署策略,其中 maxUnavailable: 0,那么 k8s 会排空节点吗?在此之前,它会在现有节点上创建新的 pod 吗? - chagan

3

4
OP正在使用策略类型RollingUpdate,因为他想要这种行为 - 不确定这个答案如何有所帮助... - Adam Hughes

1
如前所述,您可以将maxUnavailable设置为0以实现所需的结果。还有一些额外的注意事项:
  1. 当使用挂载单个特定卷供新Pod使用的有状态服务时,您不应该期望此方法有效。该卷将附加到即将被替换的Pod,因此无法附加到新的Pod。
  2. 文档指出,如果已将.spec.strategy.rollingUpdate.maxSurge设置为0,则无法将其设置为0。

https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#max-unavailable


1
那么你的意思是说,如果 Pod 上有持久卷,我们就永远不应该这样做? - Adam Hughes

0
这是在部署yaml文件中对我有效的配置。
spec:
  replicas: 1
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
    type: RollingUpdate

这将会启动第二个容器,等待它变为正常状态(确保你有启动/就绪/存活探针)。
顺便说一下,这是我们在这个应用程序中使用的探针(一个带有/health的Spring应用程序的HTTP健康检查)。
ports:
  - containerPort: 80
    name: http
startupProbe:
  successThreshold: 1
  failureThreshold: 18
  periodSeconds: 10
  timeoutSeconds: 5
  httpGet:
    path: /management/health
    port: http
readinessProbe:
  successThreshold: 2
  failureThreshold: 2
  periodSeconds: 10
  timeoutSeconds: 5
  httpGet:
    path: /management/health
    port: http
livenessProbe:
  successThreshold: 1
  failureThreshold: 3
  periodSeconds: 30
  timeoutSeconds: 5
  httpGet:
    path: /management/health
    port: http

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接