簡體   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