多容器 pod 中如何忽略容器失败?

6
我有一个多容器应用程序:应用程序 + 辅助容器。这两个容器都应该始终处于活动状态,但辅助容器并不是那么重要。
辅助容器依赖于外部资源,如果此资源不可用,则辅助容器会崩溃。它将带下整个 Pod。Kubernetes 尝试重新创建 Pod 并失败,因为现在无法启动辅助容器。
但从我的业务逻辑角度来看,辅助容器的崩溃是完全正常的。拥有辅助容器很好,但不是强制性的。
我不想让辅助容器在崩溃时带上主应用程序。
什么是最好的 Kubernetes 原生方法来实现这一点?
是否可以告诉 Kubernetes 忽略辅助容器的故障作为 "false positive" 事件,这是绝对可以接受的呢?
我在 pod 规格中找不到任何控制此行为的内容。
我的 yaml:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: myapp
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: myapp
    spec:
      volumes:
      - name: logs-dir
        emptyDir: {}
      containers:
      - name: myapp
        image: ${IMAGE}
        ports:
        - containerPort: 9009
        volumeMounts:
        - name: logs-dir
          mountPath: /usr/src/app/logs
        resources:
          limits:
            cpu: "1"
            memory: "512Mi"
        readinessProbe:
          initialDelaySeconds: 60 
          failureThreshold: 8 
          timeoutSeconds: 1
          periodSeconds: 8 
          httpGet:
            scheme: HTTP
            path: /myapp/v1/admin-service/git-info
            port: 9009
      - name: graylog-sidecar
        image: digiapulssi/graylog-sidecar:latest
        volumeMounts:
        - name: logs-dir
          mountPath: /log
        env:
        - name: GS_TAGS
          value: "[\"myapp\"]"
        - name: GS_NODE_ID
          value: "nodeid"
        - name: GS_SERVER_URL
          value: "${GRAYLOG_URL}"
        - name: GS_LIST_LOG_FILES
          value: "[\"/ctwf\"]"
        - name: GS_UPDATE_INTERVAL
          value: "10"
        resources:
          limits:
            memory: "128Mi"
            cpu: "0.1"

2
重新设计边车容器怎么样?如果外部资源不可用,它可以重试或阻塞而不是失败退出。 - larsks
@stqs,你能发布一下yaml文件吗? - garlicFrancium
@larsks,我正在考虑这个问题,但它是一些第三方的附属组件,所以我不想再添加另一个需要维护的组件,如果能直接使用它就太好了。 - Stqs
定义旁路容器的livenessProbe为no-op怎么样? - Amit Kumar Gupta
1
@garlicFrancium,样例已添加 - Stqs
4个回答

1

警告:被标记为“正确”的答案似乎不起作用。

将一个活动探针添加到应用程序容器中,并将重启策略设置为“从不”,会导致在旁路容器停止并应用程序容器未通过其活动探针的情况下,Pod 停止且永远不会重新启动。这是一个问题,因为您确实希望应用程序容器重新启动。

问题应该按以下方式解决:

  • 在启动命令中调整旁路容器以在应用程序进程失败时保持主要进程运行。这可以通过额外的脚本完成,例如通过将 | tail -f /dev/null 添加到启动命令中来实现。
  • 通常情况下,向应用程序容器添加一个活动探针是一个好主意。但请记住,它只能保护您免受应用程序进程在没有处于正确状态的情况下继续运行的影响。它肯定不会覆盖重启策略:
Container Probes:容器探针>


这个解决方案并不好。是的,sidecar容器将被保留,但如果命令失败,我们为什么需要它呢? 可能的解决方案之一是在sidecar容器中运行不是你需要的命令,而是运行你需要的命令的后台命令,并检查它是否正在运行。如果没有运行,则重新运行。 - Paval

0

一个自定义的livenessProbe应该会有所帮助,但对于您的情况,我建议使用主应用程序容器的livenessProbe,即myapp
考虑到您不关心sidecar(如上所述),我会将pod的restartPolicy设置为Never,然后为您的主要myapp定义一个自定义的livelinessProbe。这样,无论哪个容器失败,Pod都不会重新启动,但是当您的myapp容器的livenessProbe失败时,kubelet将重新启动容器!请参见下面的链接link

Pod正在运行,并具有两个容器。容器1以失败退出。

记录失败事件。如果restartPolicy为:Always:重启容器;Pod阶段保持Running。OnFailure:重启容器;Pod阶段保持Running。Never:不要重启容器;Pod阶段保持Running。

因此,更新后的(伪)yaml应如下所示:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: myapp
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    ...
    spec:
      ...
      restartPolicy: Never
      containers:
      - name: myapp
        ...
        livenessProbe:
          exec:
            command:
            - /bin/sh
            - -c
            - {{ your custom liveliness check command goes }}
          failureThreshold: 3
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        readinessProbe:
          ...
      - name: graylog-sidecar
        ...

注意:由于我不知道您的应用程序,因此我无法编写命令,但是对于我的jboss服务器,我使用了这个(为您提供一个示例)。
livenessProbe:
          exec:
            command:
            - /bin/sh
            - -c
            - /opt/jboss/wildfly/bin/jboss-cli.sh --connect --commands="read-attribute
              server-state"
          failureThreshold: 3
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1

如果我尝试这样做,我的 Pod 在存活探针失败后停止运行,这是应该的,因为 restartPolicy 是 Never。 - Fritz Duchardt
我要么得到这个错误信息:“无法识别 "my-deployment.yaml":在版本 "extensions/v1beta1" 中没有与 "Deployment" 匹配的种类”,apiVersion: extensions/v1beta1;要么得到这个错误信息:“invalid: spec.template.spec.restartPolicy: Unsupported value: "Never": supported values: "Always"”,apiVersion: apps/v1。 - anche

0
我觉得最好的解决方案不是在 sidecar 容器内失败,而是记录错误并重新运行。
#!/usr/bin/env bash

set -e
# do some stuff which can fail on start

set +e # needed to not exit if command fails

while ! command; do
    echo "command failed - rerun"
done

如果命令执行失败,它将始终重新运行command,但如果command成功完成,则退出。


它不起作用,你试图终止脚本,它将会终止命令进程并重新启动它。 - David Barda
@DavidBarda 对我来说没问题。我在旁路容器中使用类似的指标导出逻辑。我没有理解关于“你试图杀死脚本”的部分。 - Paval
@Pavel,你尝试使用sigint终止脚本了吗? - David Barda

-1

您可以为您的 sidecar 定义自定义的 livenessProbe,以便在环境中所认可的故障率超过了 failureThreshold/periodSeconds 时进行适当的调整,或者干脆忽略所有故障。

文档:

https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.15/#probe-v1-core

kubectl explain deployment.spec.template.spec.containers.livenessProbe

的意思是:解释 deployment.spec.template.spec.containers.livenessProbe 的含义。

你能具体说明如何“简单地忽略所有失败”吗?我猜这就是问题所在! - garlicFrancium
1
failureThresholdperiodSeconds的最小值均为1。我没有看到任何无限时间的通配符! - garlicFrancium
如果您设置足够大的 periodSeconds 和足够大的 failureThreshold,这将为您提供足够长的时间窗口,使容器在未重新启动的情况下保持失败状态。如果您只想拥有无限时间,则可以定义 livenessProbe.exec 运行类似于 exit 0/bin/true 的内容,以始终通过检查。来自文档: failureThreshold <integer> 在成功后,要考虑探测失败的最小连续失败次数。默认值为3。最小值为1。 - Keilo
我认为 livenessProbe 命令 exit 0/bin/true 是在特定容器内运行的,因此当容器处于活动状态时,这种方法将起作用。但是如果容器已经停止了,你该如何运行这些命令呢?你有任何示例吗? - garlicFrancium
1
@garlicFrancium 很高兴它对你有用。 "noop" 意味着 "无操作",什么也不做,更多细节请参见:https://en.wikipedia.org/wiki/NOP_(code)。而 "probe" 是指 Kubernetes 存活性和就绪探针,如此处所述:https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/,快速介绍请查看 https://www.youtube.com/watch?v=mxEvAPQRwhw。 - Keilo
显示剩余2条评论

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