繁体   English   中英

在 Kube.netes cron 作业中运行的应用程序未连接到同一 Kube.netes 集群中的数据库

[英]Application running in Kubernetes cron job does not connect to database in same Kubernetes cluster

我有一个运行 PostgreSQL 数据库的 Kube.netes 集群、一个 Grafana 仪表板和一个 Python 单次运行应用程序(构建为 Docker 图像),该应用程序每小时在 Kube.netes CronJob中运行一次(参见下面的清单)。 此外,这一切都是使用带有 Istio side-car 注入的 ArgoCD 部署的。

我遇到的问题(如标题所示)是我的 Python 应用程序无法连接到集群中的数据库。 这对我来说很奇怪,因为仪表板实际上可以连接到数据库,所以我不确定 Python 应用程序可能有什么不同。

以下是我的清单(更改了一些内容以删除可识别信息):

database.yaml的内容:

---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: database
  name: database
spec:
  replicas: 1
  selector:
    matchLabels:
      app: database
  strategy: {}
  template:
    metadata:
      labels:
        app: database
    spec:
      containers:
      - image: postgres:12.5
        imagePullPolicy: ""
        name: database
        ports:
        - containerPort: 5432
        env:
          - name: POSTGRES_DB
            valueFrom:
              secretKeyRef:
                name: postgres-secret
                key: POSTGRES_DB
          - name: POSTGRES_USER
            valueFrom:
              secretKeyRef:
                name: postgres-secret
                key: POSTGRES_USER
          - name: POSTGRES_PASSWORD
            valueFrom:
              secretKeyRef:
                name: postgres-secret
                key: POSTGRES_PASSWORD
        resources: {}
        readinessProbe:
          initialDelaySeconds: 30
          tcpSocket:
            port: 5432
      restartPolicy: Always
      serviceAccountName: ""
      volumes: null
status: {}
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: database
  name: database
spec:
  ports:
  - name: "5432"
    port: 5432
    targetPort: 5432
  selector:
    app: database
status:
  loadBalancer: {}

dashboard.yaml的内容:

---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: dashboard
  name: dashboard
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dashboard
  strategy: {}
  template:
    metadata:
      labels:
        app: dashboard
    spec:
      containers:
      - image: grafana:7.3.3
        imagePullPolicy: ""
        name: dashboard
        ports:
          - containerPort: 3000
        resources: {}
        env:
          - name: POSTGRES_DB
            valueFrom:
              secretKeyRef:
                name: postgres-secret
                key: POSTGRES_DB
          - name: POSTGRES_USER
            valueFrom:
              secretKeyRef:
                name: postgres-secret
                key: POSTGRES_USER
          - name: POSTGRES_PASSWORD
            valueFrom:
              secretKeyRef:
                name: postgres-secret
                key: POSTGRES_PASSWORD
        volumeMounts:
          - name: grafana-datasource
            mountPath: /etc/grafana/provisioning/datasources
        readinessProbe:
          initialDelaySeconds: 30
          httpGet:
            path: /
            port: 3000
      restartPolicy: Always
      serviceAccountName: ""
      volumes:
        - name: grafana-datasource
          configMap:
            defaultMode: 420
            name: grafana-datasource
        - name: grafana-dashboard-provision
status: {}
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: dashboard
  name: dashboard
spec:
  ports:
  - name: "3000"
    port: 3000
    targetPort: 3000
  selector:
    app: dashboard
status:
  loadBalancer: {}

cronjob.yaml的内容:

---
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: python
spec:
  concurrencyPolicy: Replace
  # TODO: Go back to hourly when finished testing/troubleshooting
  # schedule: "@hourly"
  schedule: "*/15 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - image: python-tool:1.0.5
            imagePullPolicy: ""
            name: python
            args: []
            command:
              - /bin/sh
              - -c
              - >-
                echo "$(POSTGRES_USER)" > creds/db.creds;
                echo "$(POSTGRES_PASSWORD)" >> creds/db.creds;
                echo "$(SERVICE1_TOKEN)" > creds/service1.creds;
                echo "$(SERVICE2_TOKEN)" > creds/service2.creds;
                echo "$(SERVICE3_TOKEN)" > creds/service3.creds;
                python3 -u main.py;
                echo "Job finished with exit code $?";
            env:
              - name: POSTGRES_DB
                valueFrom:
                  secretKeyRef:
                    name: postgres-secret
                    key: POSTGRES_DB
              - name: POSTGRES_USER
                valueFrom:
                  secretKeyRef:
                    name: postgres-secret
                    key: POSTGRES_USER
              - name: POSTGRES_PASSWORD
                valueFrom:
                  secretKeyRef:
                    name: postgres-secret
                    key: POSTGRES_PASSWORD
              - name: SERVICE1_TOKEN
                valueFrom:
                  secretKeyRef:
                    name: api-tokens-secret
                    key: SERVICE1_TOKEN
              - name: SERVICE2_TOKEN
                valueFrom:
                  secretKeyRef:
                    name: api-tokens-secret
                    key: SERVICE2_TOKEN
              - name: SERVICE3_TOKEN
                valueFrom:
                  secretKeyRef:
                    name: api-tokens-secret
                    key: SERVICE3_TOKEN
          restartPolicy: OnFailure
          serviceAccountName: ""
status: {}

现在,正如我提到的,Istio 也是这张图片的一部分,所以我有一个用于仪表板的虚拟服务,因为它应该可以在集群外部访问,但仅此而已。

把所有这些都解决了,这就是我自己所做的尝试和解决这个问题的方法:

  1. 确认CronJob正在使用正确的连接设置(即主机、数据库名称、用户名和密码)连接到数据库。

    为此,我向CronJob部署添加了 echo 语句,显示用户名和密码(我知道,我知道),它们是预期值。 我也知道这些是数据库的正确连接设置,因为我逐字使用它们将仪表板连接到数据库,从而成功连接。

    Grafana 仪表盘的数据源设置:

    Grafana 数据源使用的连接设置

    来自 Python 应用程序的错误消息(显示在容器的 ArgoCD 日志中):

    cron 作业使用的连接设置

  2. 考虑到 Istio 可能会导致此问题,我尝试为CronJob资源禁用 Istio side-car 注入(通过将此注释添加到metadata.annotations部分: sidecar.istio.io/inject: false )但注释实际上从未出现在Argo 日志,并且在CronJob运行时没有观察到任何变化。

  3. 我尝试在运行 Python 脚本的CronJob容器中kubectl exec以进行更多调试,但实际上从来没有能够做到,因为一旦发生连接错误,容器就会退出。

就是说,在这方面我已经用我的头撞墙够久了。 谁能发现我可能遗漏的东西并指出正确的方向,好吗?

我认为问题在于您的 pod 在 istio sidecar 准备好之前尝试连接到数据库。 因此无法建立连接。

Istio 运行一个初始化容器来配置 pod 路由表,因此所有流量都通过 sidecar 进行路由。 因此,如果 sidecar 没有运行并且另一个 pod 尝试连接到数据库,则无法建立连接。

有两种解决方法。

首先,您的工作可以等待 30 秒,然后再使用一些睡眠命令调用main.py

或者,您可以启用holdApplicationUntilProxyStarts 通过这个主容器将不会启动,直到边车运行。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM