0

我有一个带有两个配置文件 dev 和 prod 的 spring boot 应用程序,我的 docker 文件是:

FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG DEPENDENCY=target/dependency
COPY ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY ${DEPENDENCY}/META-INF /app/META-INF
COPY ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-Dspring.profiles.active=dev","-cp","app:app/lib/*","com.my.Application"]

请不要这样,在构建图像时,我将入口点指定为命令行参数。

这是我使用此映像的 kubernetes 部署的容器部分:

containers:
  - name: myapp
    image: myregistry.azurecr.io/myapp:0.1.7
    imagePullPolicy: "Always"
    ports:
    - containerPort: 8080
      name: myapp
    readinessProbe:
      httpGet:
        path: /actuator/health
        port: 8080
      timeoutSeconds: 3
      periodSeconds: 20
      failureThreshold: 3

它可以工作,但有一个重大缺陷:我现在如何在不重建映像的情况下切换到生产环境?

最好的办法是在我的 docker 文件中删除该 ENTRYPOINT 并在我的 kubernetes yml 中提供此配置,以便我始终可以使用相同的图像......这可能吗?

编辑:我看到有一个生命周期指令,但请注意我有一个基于弹簧靴执行器的就绪探针。如果我使用这个结构,它总是会失败。

4

4 回答 4

3

您可以ENTRYPOINT使用commandKubernetes Pod 规范的属性覆盖图像。CMD同样,您可以使用该args属性覆盖(另请参阅文档):

containers:
- name: myapp
  image: myregistry.azurecr.io/myapp:0.1.7
  imagePullPolicy: "Always"
  command: ["java","-Dspring.profiles.active=prod","-cp","app:app/lib/*","com.my.Application"]
  ports:
  - containerPort: 8080
    name: myapp

或者,为了提供更高级别的抽象,您可以编写自己的入口点脚本,从环境变量中读取应用程序配置文件:

#!/bin/sh

PROFILE="${APPLICATION_CONTEXT:-dev}"
exec java "-Dspring.profiles.active=$PROFILE" -cp app:app/lib/* com.my.Application

然后,您可以简单地将该环境变量传递到您的 pod 中:

containers:
- name: myapp
  image: myregistry.azurecr.io/myapp:0.1.7
  imagePullPolicy: "Always"
  env:
  - name: APPLICATION_CONTEXT
    value: prod
  ports:
  - containerPort: 8080
    name: myapp
于 2019-07-21T09:35:53.890 回答
2

而不是将spring.profiles.activedockerfile 放入入口点。

利用configmapsapplication.properties

您在 dockerfile 中的 ENTRYPOINT 应如下所示:

ENTRYPOINT ["java","-cp","app:app/lib/*","com.my.Application","--spring.config.additional-location=/config/application-dev.properties"]

为您的 springboot 应用程序创建一个充当 application.properties 的 configmap

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: myapp-config
  namespace: flow
data:
  application-dev.properties: |
    spring.application.name=myapp
    server.port=8080
    spring.profiles.active=dev

注意:这里我们指定了 spring.profiles.active。

在我的 kubernetes 部署的容器部分中,将 configmap 安装在容器内,该容器将充当 application.properties。

containers:
  - name: myapp
    image: myregistry.azurecr.io/myapp:0.1.7
    imagePullPolicy: "Always"
    command: ["java","-cp","app:app/lib/*","com.my.Application","--spring.config.additional-location=/config/application-dev.properties"]
    ports:
    - containerPort: 8080
      name: myapp
    volumeMounts:
    - name: myapp-application-config
      mountPath: "/config"
      readOnly: true
    volumes:
    - name: myapp-application-config
      configMap:
        name: myapp-config
        items:
        - key: application-dev.properties
          path: application-dev.properties
    readinessProbe:
      httpGet:
        path: /actuator/health
        port: 8080
      timeoutSeconds: 3
      periodSeconds: 20
      failureThreshold: 3

注意:--spring.config.additional-location指向我们在 configmaps 中创建的 application.properties 的位置。

因此,使用 configmaps 和 application.properties 可以覆盖应用程序的任何配置,而无需重建映像。

如果要添加新配置或更新现有配置的值,只需在 configmap 及其中进行适当的更改kubectl apply。然后缩小和扩大您的应用程序 pod,以使新配置生效。

希望这可以帮助。

于 2019-07-21T09:56:32.060 回答
1

很多方法可以设置 Spring 配置值。通过一些规则,您可以使用普通环境变量来指定单个属性值。您可能会看到是否可以使用它而不是使用单独的 Spring 配置文件控件。

在这里使用环境变量有两个好处:这意味着您(或您的 DevOps 团队)可以更改部署时设置而无需重新编译应用程序;如果您使用像Helm这样的部署管理器,其中主机名等一些细节本质上是不可预测的,那么这可以让您指定在部署之前无法知道的值。

例如,假设您有一个 Redis 依赖项:

cache:
  redis:
    url: redis://localhost:6379/0

您可以通过设置在部署时覆盖它

containers:
  - name: myapp
    env:
      - name: CACHE_REDIS_URL
        value: "redis://myapp-redis.default.svc.cluster.local:6379/0"
于 2019-07-21T10:40:52.457 回答
0

一种方法是使用spring cloud Kubernetes,如此处所述 https://docs.spring.io/spring-cloud-kubernetes/docs/current/reference/html/index.html#configmap-propertysource

您可以在 configmap 中定义您的配置文件,如下所示

kind: ConfigMap
apiVersion: v1
metadata:
  name: demo
data:
  application.yml: |-
    greeting:
      message: Say Hello to the World
    farewell:
      message: Say Goodbye
    ---
    spring:
      profiles: development
    greeting:
      message: Say Hello to the Developers
    farewell:
      message: Say Goodbye to the Developers
    ---
    spring:
      profiles: production
    greeting:
      message: Say Hello to the Ops

然后可以通过在 Kubernetes 部署清单中传递环境变量来选择所需的配置文件

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-name
  labels:
    app: deployment-name
spec:
  replicas: 1
  selector:
    matchLabels:
      app: deployment-name
  template:
    metadata:
      labels:
        app: deployment-name
    spec:
        containers:
        - name: container-name
          image: your-image
          env:
          - name: SPRING_PROFILES_ACTIVE
            value: "development"
于 2021-02-14T17:05:57.480 回答