kubernetes集群中如何正确配置环境?

How to properly configure the environment in kubernetes cluster?

我有一个 spring 启动应用程序,它有两个配置文件,dev 和 prod,我的 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 中提供这个配置,这样我就可以始终使用相同的图像...这可能吗?

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

您可以使用 Kubernetes Pod 规范的 command 属性 覆盖图像的 ENTRYPOINT。同样,您可以使用 args 属性(另请参阅 the documentation)覆盖 CMD

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

而不是将 spring.profiles.active 放在入口点的 dockerfile 中。

利用configmaps and application.properties.

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

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

为您的 springboot 应用程序创建一个充当 application.properties 的配置映射

---
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 指向我们在配置映射中创建的 application.properties 的位置。

因此,使用 configmaps 和 application.properties 可以在不重建映像的情况下覆盖应用程序的任何配置。

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

希望对您有所帮助。

many many ways to set Spring configuration values. With some rules,可以使用普通的环境变量来指定个别的属性值。您可能会看到是否可以使用它来代替单独的 Spring 配置文件控制。

在这里使用环境变量有两个优点:这意味着您(或您的 DevOps 团队)可以更改 deploy-time 设置而无需重新编译应用程序;如果您使用像 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"

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

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

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 部署清单中传递环境变量来 select 所需的配置文件

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"