Dockerized Spring Boot 应用程序不使用已安装的 Kubernetes ConfigMap (application.properties)

Posted

技术标签:

【中文标题】Dockerized Spring Boot 应用程序不使用已安装的 Kubernetes ConfigMap (application.properties)【英文标题】:Dockerized Spring Boot app not using mounted Kubernetes ConfigMap (application.properties) 【发布时间】:2020-03-29 22:59:50 【问题描述】:

我有一个问题,在我的 dockerized Spring Boot 应用程序中没有使用我存储在 configMap 中的 application.properties

但是,当我进入 Pod 的 shell 时,我可以看到并确认我的 configMap 已正确挂载在我的 Spring Boot 应用程序的正确目录中。

请注意,默认情况下我有一个 application.properties,其中 Kubernetes 稍后会挂载/覆盖它。

似乎Spring Boot使用了第一个application.properties,当k8s覆盖它时,显然它没有使用它。

看来,显然,发生的事情是:

在 Dockerized Spring Boot 应用程序中运行 .jar 文件 在运行时使用第一个/默认 application.properties 文件 Kubernetes 继续挂载configMap 挂载/覆盖成功,但是 Spring Boot 已经运行了,如何使用它?

这里是我的 Spring Boot / Docker 镜像的 Dockerfile 供参考:

FROM maven:3.5.4-jdk-8-alpine

# Copy whole source code to the docker image
# Note of .dockerignore, this ensures that folders such as `target` is not copied
WORKDIR /usr/src/myproject
COPY . /usr/src/myproject/

RUN mvn clean package -DskipTests

WORKDIR /usr/src/my-project-app
RUN cp /usr/src/myproject/target/*.jar ./my-project-app.jar
EXPOSE 8080
CMD ["java", "-jar", "my-project-app.jar"]

这是我的 Kubernetes 部署 .yaml 文件供参考:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: my-project-api
  namespace: my-cluster
  labels:
    app: my-project-api
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-project-api
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: my-project-api
    spec:
      containers:
        - name: my-project-api
          image: "my-project:latest"
          imagePullPolicy: Always
          env:
            .
            .
            .
          volumeMounts:
          - name: my-project-config
            mountPath: /usr/src/my-project/my-project-service/src/main/resources/config/application.properties
          ports:
            - containerPort: 8080
              name: my-project-api
              protocol: TCP
      volumes:
        # Name of the volume
        - name: my-project-config
          # Get a ConfigMap with this name and attach to this volume
          configMap:
            name: my-project-config

还有我的 configMap 供参考:

kind: ConfigMap
apiVersion: v1
data:
  application.properties: |-
    # This comment means that this is coming from k8s ConfigMap. Nice!
    server.port=8999
    .
    .
    .
    .

metadata:
  name: my-project-config
  namespace: my-cluster

非常感谢任何帮助...非常感谢您.. :)

【问题讨论】:

只是想知道:a) 您是否尝试过仅使用目录作为挂载? IE。 /usr/src/my-project/my-project-service/src/main/resources/config/? b) 您是否可以不提供默认的application.propertiesc) 您是否考虑/尝试过 K8s 中 lifecycle 中的 postStart 挂钩来运行您的应用程序?而不是通过Dockerfile 进行。如果是这样,您是否看到应用读取正确配置的任何变化? 嗨@KenFlake,我在*** 上找到了这个post,它可能会回答你的问题。让我知道是否有帮助。 嗨@yvesonline,您是否有一个示例代码sn-p 可以使用postStart 在k8s 部署文件中运行.jar 文件?因为不知道长什么样子,只知道在Dockerfile里面运行.jar文件=) 您好@jt97,我已经查看了您的建议,非常感谢您的回复。但正如我所看到的,我看到 SO 帖子和我的 Dockerfile 配置非常相似。我不知道在我的 Dockerfile 版本上编辑什么... =) 您可以在 kubernetes.io/docs/tasks/configure-pod-container/… 中阅读有关它的信息,并在您的 deployment.yaml 中进行操作,将类似于 lifecycle: postStart: exec: command: ... 的内容添加到您的容器规范中。确保不要在您的 Dockerfile 中启动您的应用程序,然后让容器在那里闲置。 【参考方案1】:

问题是您的应用程序使用的/src/main/resources/application.properties 是默认情况下在 jar 文件中的那个。如果你打开你的罐子,你应该在那里看到它。 话虽如此,不幸的是,您希望在 jar 所在的位置上挂载 /src/main/resources 目录的期望不会实现。 These are the docs you should be looking at。

我不会详细说明它在文档中的解释很好,但我会说你最好明确声明你的配置位置,以便项目中的新人知道配置来自哪里球棒。

你可以这样做:

---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: my-project-api
  labels:
    app: my-project-api
spec:
  selector:
    matchLabels:
      app: my-project-api
  template:
    metadata:
      labels:
        app: my-project-api
    spec:
      containers:
        - name: my-project-api
          image: "my-project:latest"
          imagePullPolicy: Always
          env:
            - name: JAVA_OPTS
              value: "-Dspring.config.location=/opt/config"
            .
            .
            .
          volumeMounts:
            - name: my-project-config
              mountPath: /opt/config
          ports:
            - containerPort: 8080
      volumes:
        - name: my-project-config
          configMap:
            name: my-project-config

希望对你有帮助,

干杯!

【讨论】:

嗨,乌罗什。感谢您的回答!我选择在 Pod 运行时使用 SPRING_PROFILES_ACTIVE 来激活我的 app.properties。【参考方案2】:

我的做法略有不同。我确定我已经在 config/.properties 挂载了 application.properties。 IE;下面是我安装的 application.properties 示例(下面的命令显示 pod 中的值 - 即,在 kubectl exec -it 进入 pod 之后)

/ # pwd
/
/ # cat config/application.properties 
logback.access.enabled=false
management.endpoints.web.exposure.include=health, loggers, beans, configprops, env

基本上,诀窍is based on the link in the above answer。下面是链接的摘录,其中确实说 application.properties 将从 config/ 中选择。所以,我确保我的环境(开发、测试、产品)特定的配置映射安装在 config/.请注意以下列表有优先权(根据链接:列表中较高的位置覆盖较低的项目)

A /config subdir of the current directory.
The current directory
A classpath /config package
The classpath root

下面是配置映射定义(刚刚粘贴的数据部分)

data:
  application.properties: |+
    logback.access.enabled=.Values.logacbkAccessEnabled
    management.endpoints.web.exposure.include=health, loggers, beans, configprops, env

您还可以从 actuator/env 端点看到 SpringBootApp 确实选择了这些值。


"name": "Config resource 'file [config/application.properties]' via location 'optional:file:./config/'",
"properties": 
"logback.access.enabled": 
"value": "false",
"origin": "URL [file:config/application.properties] - 1:24"
,
"management.endpoints.web.exposure.include": 
"value": "health, loggers, beans, configprops, env",
"origin": "URL [file:config/application.properties] - 2:43"


,

【讨论】:

以上是关于Dockerized Spring Boot 应用程序不使用已安装的 Kubernetes ConfigMap (application.properties)的主要内容,如果未能解决你的问题,请参考以下文章

dockerized 环境中的 Keycloak 和 Spring Boot Web 应用程序

Dockerized Spring boot 和 Zuul

Dockerized Spring Boot 应用程序连接到主 MySQL [重复]

java.net.UnknownHostException 来自 Spring Boot 应用程序的 dockerized mysql

Dockerized Spring Boot 应用程序不使用已安装的 Kubernetes ConfigMap (application.properties)

将外部 application.properties 文件添加到 tomcat 内的 dockerized spring boot web 应用程序