Spring Boot App 无法使用来自 Kubernetes 机密的凭据访问 Postgres [英] Spring Boot App can't access Postgres using credentials from Kubernetes secret

查看:33
本文介绍了Spring Boot App 无法使用来自 Kubernetes 机密的凭据访问 Postgres的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不是 Kubernetes 的专家,因此,为了学习,我开始构建一个简单的 Spring Boot Web 应用程序(称为膳食计划器),它读取和写入 PostgreSQL 数据库.Postgres 和 Spring Boot 应用程序部署在 Kubernetes 中,Kubernetes 运行在(当前)2 个 Raspberry Pi(3 和 3B+)上.我在命名空间 home 中工作,并为每个(Postgres 和 Spring Boot Appl.)创建了一个部署和服务.我创建了一个秘密定义凭据,用于在 Spring Boot Appl 中创建 DB 和 DB-Credentials.有效地,我不会将 DB 放在 Kubernetes 集群中,但是对于 Pi,我不在乎,因为数据一文不值.

I'm not an expert when it comes to Kubernetes so, for learning, I started building a simple Spring Boot Web-App (called meal-planner) which reads and writes to a PostgreSQL DB. Postgres and Spring Boot app are deployed in Kubernetes which is running on (currently) 2 Raspberry Pis (3 and 3B+). I work in the namespace home and have created a Deployment and Service for each (Postgres and Spring Boot Appl.). I have created a secret defining credentials which I use to create the DB and as DB-Credentials in the Spring Boot Appl. Productively, I wouldn't put the DB in the Kubernetes Cluster, but with the Pi, I don't care since the data is worthless.

描述秘密收益:

Name:         dev-db-secret
Namespace:    home
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
password:  20 bytes
username:  7 bytes

application.yaml 如下:

spring:
  jpa:
    database-platform: org.hibernate.dialect.PostgreSQLDialect
    open-in-view: false
    hibernate:
      ddl-auto: update
  datasource:
    url: "jdbc:postgresql://postgres:5432/home"
    username: ${DB_USER}
    password: ${DB_PASSWORD}

我使用以下 Dockerfile 来构建 Spring Boot 应用程序:

I used the following Dockerfile for building the Spring Boot Appl.:

FROM arm32v7/openjdk:11-jdk
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

并使用 docker buildx build --platform linux/arm/v7 -t ... --push 在 Windows 10 PC 上构建它.Kubernetes 找到并部署它就好了.

And build it on a Windows 10 PC using docker buildx build --platform linux/arm/v7 -t ... --push. Kubernetes finds and deploys it just fine.

以下是 Postgres-DB 的服务和部署:

The following is the Service and Deployment for the Postgres-DB:

kind: Service
apiVersion: v1
metadata:
  name: postgres
  namespace: home
  labels:
    app: postgres
spec:
  type: NodePort
  selector:
    app: postgres
  ports:
    - port: 5432
      targetPort: 5432
      name: postgres
---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: postgres
  namespace: home
spec:
  replicas: 1
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
        - name: postgres
          image: postgres:13.2
          imagePullPolicy: IfNotPresent
          env:
            - name: POSTGRES_USER
              valueFrom:
                secretKeyRef:
                  name: dev-db-secret
                  key: username
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: dev-db-secret
                  key: password
            - name: POSTGRES_DB
              value: home
          ports:
            - containerPort: 5432
          volumeMounts:
            - mountPath: /var/lib/postgresql/data
              name: postgres-data
      volumes:
        - name: postgres-data
          persistentVolumeClaim:
            claimName: postgres-pv-claim
---

部署工作正常,我可以使用 SQL 客户端(如 DBeaver)使用 dev-db-secret 密码中的凭据访问数据库(当我使用 <代码>kubectl port-forward service/postgres -n home 5432:5432)

The deployment works fine and I can access the Database using a SQL-Client (like DBeaver) using the credentials in the dev-db-secret secret (when I port-forward the service using kubectl port-forward service/postgres -n home 5432:5432)

我将以下部署描述符用于 Spring-Boot 应用程序.

I use the following deployment descriptor for the Spring-Boot Appl.

kind: Service
apiVersion: v1
metadata:
  name: meal-planner
  namespace: home
  labels:
    app: meal-planner
spec:
  type: NodePort
  selector:
    app: meal-planner
  ports:
    - port: 8080
      targetPort: 8080
      name: meal-planner
---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: meal-planner
  namespace: home
spec:
  replicas: 1
  selector:
    matchLabels:
      app: meal-planner
  template:
    metadata:
      labels:
        app: meal-planner
    spec:
      containers:
        - name: meal-planner
          image: 08021986/meal-planner:v1
          imagePullPolicy: Always
          env:
            - name: DB_USER
              valueFrom:
                secretKeyRef:
                  name: dev-db-secret
                  key: username
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: dev-db-secret
                  key: password
          ports:
            - containerPort: 8080
---

应用程序部署并启动得很好.但是,当我 kubectl port-forward service/meal-planner -n home 8080:8080 并调用从 DB 读取所有数据"-端点时,我收到以下错误:

The application deploys and starts just fine. However when I kubectl port-forward service/meal-planner -n home 8080:8080 and call the "Read all data from DB"-Endpoint, I get the following error:

...
Caused by: org.hibernate.exception.GenericJDBCException: Unable to open JDBC Connection for DDL execution
...
Caused by: org.postgresql.util.PSQLException: FATAL: password authentication failed for user "<<username from secret>>"

当我在本地启动应用程序时,端口转发 DB-Service(并将 application.yaml 中的数据源 url 替换为 jdbc:localhost://postgres:5432/home),一切正常完美运行.

When I start the application locally, port-forward the DB-Service (and replace the datasource url in the application.yaml with jdbc:localhost://postgres:5432/home), everything works perfectly.

我不明白为什么 Postgres 使用秘密来创建凭据 - 这显然是有效的,因为我可以使用客户端或本地运行的应用程序访问数据库,但 Spring 的身份验证失败 -引导服务(它似乎仍然能够从秘密中获取用户名).我做错了什么?

为了部署描述符的完整性,这里是命名空间、持久卷和声明描述符:

For completeness of the deplyoment descriptors, here the namespace, persistent volume and claim descriptor:

apiVersion: v1
kind: Namespace
metadata:
  name: home
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-volume
  namespace: home
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/data"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgres-pv-claim
  namespace: home
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi

代码可以在 https://github.com/Urr4/deploymentshttps://github.com/Urr4/meal-planner

更新:在完全删除机密并将凭据手动添加到 application.yaml 后,我仍然遇到相同的错误.我现在假设,我无法从膳食计划者 pod 访问 postgres 服务,这意味着 Servcie 无法连接到数据库,因此无法通过身份验证,而不是因为凭据.我试过 kubectl exec <<meal-planner-pod-id>>-n home -- ping postgres:5432 并得到 ping: postgres:5432: Name or service not known.我也试过 postgres.default:5432postgres.home:5432 没有成功.运行 k exec <>-n home -- wget -O- postgres 产生 Connecting to postgres (postgres)|10.43.62.32|:80... failed: Network is unreachable. 听起来像一个错误,我不知道如何解决.

Update: After completely removing the secret and adding the credentials by hand to the application.yaml, I still get the same error. I'm now assuming, that I cant reach the postgres service from the meal-planner pod, meaning the Servcie can'T connect to the DB and thus failes authenticatrion, not because of credentials. I tried kubectl exec <<meal-planner-pod-id>> -n home -- ping postgres:5432 and got ping: postgres:5432: Name or service not known. I also tried postgres.default:5432 and postgres.home:5432 without success. Running k exec <<meal-planner-pod-id>> -n home -- wget -O- postgres yields Connecting to postgres (postgres)|10.43.62.32|:80... failed: Network is unreachable. which sounds like an error, which I don't know how to fix.

我还是不知道是什么问题.

更新:我已经启动了一个 busybox,因为我无法防止餐刨机崩溃和 kubectl exec -it 进入 busybox pod 并执行 telnet postgres.home 5432 产生 telnet 连接.wget -O- postgres.home 仍然产生 网络无法访问.我在餐刨机 pod 上尝试了 telnet,但它只是告诉我 telnet:未找到.我认为 postgres(或 postgres.home)是正确的 DNS 名称,因为在这种情况下我得到 Network is unreachable.对于不存在的服务,我得到 Name or service not known.我目前认为存在某种阻止 Pod 通信的网络问题,但我不知道如何找到并解决此问题.

Update: I've started a busybox because I cant prevent the meal-planer from crashing and kubectl exec -it into the busybox pod and execute telnet postgres.home 5432 which yields telnet connected. wget -O- postgres.home still yields Network is unreachable. I tried telnet on the meal-planer pod, but it just tells me telnet: not found. I think postgres (or postgres.home) is the right DNS name, since in that case I get the Network is unreachable. For non-existent services I get Name or service not known. I currently think there is some kind of network issue which prevents pods from communicating, but I don't know how to find and fix this.

更新:在完全错误的方向上调试之后,我将关闭这个问题,以支持再次提问,但更精确、更小.可以在此处

Update: After debugging in the completely wrong direction, I'm going to close this question in favor of asking it again but more precisely and smaller. The new question can be found here

推荐答案

为 postgres 创建的服务应该是 ClusterIP 类型.如果您使用 NodePort,您将能够使用 NodeIP:NodePort 访问 postgres.由于两个实例都在命名空间内,您可以将类型更改为 ClusterIP

Service created for postgres should be of type ClusterIP. If you are using NodePort, you will be able to access postgres using NodeIP:NodePort. Since both the instances are within the namespace, you can change type to ClusterIP

此外,您可以在部署膳食计划器中更改环境变量名称.

Also, you can change the env variable name in the deployment meal-planner.

DB_USER ->用户名

DB_USER -> username

DB_PASSWORD ->密码

DB_PASSWORD -> password

这篇关于Spring Boot App 无法使用来自 Kubernetes 机密的凭据访问 Postgres的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆