Kubernetes多环境配置映射

16

我正在尝试使用来自Kubernetes集群的配置数据部署Spring Boot应用程序。我有一个简单的RestController,通过从Kubernetes集群中读取内容打印一条消息。

    private String message = "Message not coming from Kubernetes config map";

@RequestMapping(value="/echo", method=GET)
public String printKubeConfig() {
    return message;
}

在我的application.yml中指定了配置映射的名称

spring:
  application:
    name: echo-configmap
apiVersion: v1
kind: ConfigMap
metadata:
  name: echo-configmap
data:
  application.properties: |-
    message=Hello from dev Kubernetes Configmap
  application_qa.properties: |-
    message=Hello from qa Kubernetes Configmap

我有几个环境,例如qa、int、test等。

  1. 在配置映射中指定特定于环境的属性的最佳方法是什么?如何在Spring Boot应用程序中访问它们?
    例如:如果应用程序部署在qa中,则我的服务应返回消息“Hello from qa Kubernetes Configmap”。
  2. 我们还计划从GIT中读取这些配置文件。如何处理这种情况?
5个回答

9

让我尝试提供一个答案,我认为这可以给你所需的内容,而不使用除大多数计算机上已安装的工具之外的任何工具。也许首先尝试这个方法,如果发现该方法难以管理和扩展,请转向更复杂的方法。

步骤1:按环境版本控制configmaps

创建一个类似于k8s/configmaps的文件夹,并为每个环境创建一个configmap:

k8s/configmaps/properties.dev.yaml
k8s/configmaps/properties.qa.yaml
k8s/configmaps/properties.sit.yaml
k8s/configmaps/properties.uat.yaml

每个configmap都应包含您环境特定的设置。

步骤2:每个环境使用一个命名空间

为每个环境创建一个k8s命名空间,例如:

 application-dev
 application-qa
 application-sit
 application-uat

步骤3:根据环境创建配置映射

这里需要一些bash命令的帮助:

#!/usr/bin/env bash
# apply-configmaps.sh
namespace="application-${ENVIRONMENT}"
for configmap in ./k8s/configmaps/*.${ENVIRONMENT}.yml; do
    echo "Processing ConfigMap $configmap"
    kubectl apply -n ${namespace} -f $configmap
done

现在,您只需要执行以下操作即可创建或更新任何环境的配置映射:
ENVIRONMENT=dev ./update-configmaps.sh

步骤四:使用CI/CD完成工作

现在,您可以创建一个CI/CD流水线 - 如果您的配置映射源发生更改,只需运行上面显示的命令即可。

总结

基于原始命令和没有特殊工具,您可以:

  • 版本控制配置
  • 按环境管理配置
  • 在配置代码更改时更新或创建配置
  • 如果需要,可以轻松地在CI/CD流水线中应用相同的方法

我强烈建议您在跳入更复杂的工具来解决相同问题之前,遵循这种基本的“第一原则”方法,在许多情况下,您可以自己轻松解决问题,学习关键概念并将更复杂的工具保留到以后(如果确实需要)。

希望这有所帮助!


谢谢您的建议!Spring Boot应用程序只需要配置映射的名称。我们可以将此参数作为命令行参数传递给应用程序吗?还有其他建议吗?spring: application: name: echo-configmap - A V
抱歉 @AV,你是什么意思?通常情况下,如果你有一个配置映射,你可以直接将它的值作为一组环境变量挂载到应用程序进程上,或者将配置映射挂载到容器文件系统中,这样你的应用程序就可以从(例如)'/etc/myapp/config'加载它,类似于这样:https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#populate-a-volume-with-data-stored-in-a-configmap。 - Dave Kerr
关于这个问题的后续提问。如果有一些属性在所有环境中都相同,而我们不想在每个配置映射中重复它们,那么我们该如何放置这些公共属性? - A V
@AV 可能只需创建一个名为“shared”的配置映射,并将其中的值挂载到每个容器中。 - Dave Kerr
嗨@DaveKerr:我也遇到了同样的问题。我没有使用helm。我在单个配置映射中有多个配置文件(如此问题中所述)。但是,尽管我激活了其他一些配置文件,但Spring Boot应用程序仅从application.properties中获取值。这里有什么线索吗?提前致谢。 - NANDAKUMAR THANGAVELU

8
这似乎是Helm的一个很好的用例。您可以将应用程序部署为Helm Chart,这基本上允许您从模板生成Kubernetes资源(如ConfigMaps、Deployments和其他所需资源)。
您可以使用Helm Charts文档开始使用Helm。使用helm create创建Chart之后,您将获得一个templates/目录,在其中可以放置以下ConfigMap的YAML模板:
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ printf "%s-%s" .Release.Name .Chart.Name }}
  labels:
    app: {{ .Chart.Name | trunc 63 | trimSuffix "-" }}
    chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
    release: {{ .Release.Name }}
    heritage: {{ .Release.Service }}
data:
  application.properties: |-
    message={{ .Values.properties.message }}

您可以为Deployment对象添加第二个YAML模板(实际上,helm create已经创建了一个合理的默认部署)。只需在此处将ConfigMap作为卷添加即可:
containers:
  - name: {{ .Chart.Name }}
    # [...]
    volumes:
      - name: property-volume
        mountPath: /etc/your-app/properties
volumes:
  - name: property-volume
    configMap:
      name: {{ printf "%s-%s" .Release.Name .Chart.Name }}

每个 Helm chart 都有一个 values.yaml 文件,您可以在其中定义默认值,这些默认值然后用于填充模板。这个默认文件可能看起来像这样(请记住,上面的 ConfigMap 模板包含一个 {{ .Values.properties.message }} 表达式):
replicaCount: 1
image:
  repository: your-docker-image
  tag: your-docker-tag
properties:
  message: Hello!

接下来,使用该Helm图表以及helm install命令多次部署您的应用程序,并且可以使用不同的配置。您可以提供不同的YAML文件,其中覆盖来自values.yaml文件的特定值,或者使用--set覆盖单个值:

$ helm install --name dev --set image.tag=latest --set replicaCount=1 path/to/chart
$ helm install --name prod --set image.tag=stable --set replicaCount=3 --set properties.message="Hello from prod" path/to/chart

关于您的第二个问题:当然应该将您的Helm Chart放入版本控制中。然后,您可以使用helm upgrade命令来对已部署的应用程序应用更改。

感谢您的回复。我们正在尝试坚持基本的Kubernetes概念并查看它们的运作方式。Helm听起来是个好主意。我们需要做一个原型。 - A V

2

我会为每个非机密数据的git项目使用这个工具。 https://github.com/kubernetes-sigs/kustomize

在元数据中,您可以过滤您的Pods。

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: mycomponent
    env: dev
    tier: backend
  name: mycomponent
  namespace: myapplication

使用 kubectl 命令获取属于 myapplication 命名空间下 env=dev、tier=backend 以及 app=mycomponent 标签的 Pod。


1
通常情况下,您希望在 qa 上运行的应用程序不会干扰在 production 上运行的应用程序。使用 Kubernetes,您可以通过 为不同环境使用不同的命名空间 来实现这种隔离。
这样,prod 命名空间上的对象与 qa 命名空间上的对象是不同的。另一种更昂贵的方法是为不同的环境使用不同的 k8s 集群。
有了这个设置,您将在特定环境的命名空间中部署您的应用程序,并在该命名空间中创建 Deployment 对象。该 Deployment 将使用包含 Spring Boot 属性的 ConfigMap 对象。例如,我们称这个 ConfigMapecho-properties
这样,每个命名空间都将有一个唯一的 echo-properties ConfigMap 副本。每个副本都包含其所属环境的特定配置。 Deployment对象通过使用环境变量或读取文件来消耗ConfigMap属性。这里重要的是,如果更改了echo-propertiesConfigMap数据,默认情况下您的应用程序将看不到这些新值。目前为止,Kubernetes没有这个功能。您不能将ConfigMap与Spring Cloud Config进行比较,后者是一种动态配置解决方案。
一个类似但不完全相同的方法是在您的集群上使用fabric8 ConfigMap Controller。这个控制器是在您的集群上运行的进程,它会在ConfigMap更改时重新启动您的应用程序,以便读取新的配置值。
如果您不想在配置更改时重新启动应用程序,那么您可能应该坚持使用Spring Cloud Config来处理可能更改的值,并使用ConfigMaps来处理其他不会更改的属性,如应用程序名称或端口。

谢谢。我们计划使用fabric8配置库 https://github.com/spring-cloud-incubator/spring-cloud-kubernetes 来检测配置映射的更改并动态重新加载它们。由于Spring应用程序在application.yml中采用配置映射的名称,唯一的问题是如何根据环境动态更改它。spring: application: name: echo-configmap - A V
正如答案中所解释的那样,您可以为不同的环境设置不同的命名空间。每个命名空间都有自己的echo-configmap。这样做不就解决了您的问题吗? - Jose Armesto

0

你的使用场景听起来非常像是应该看一下 spring-cloud-config - https://cloud.spring.io/spring-cloud-config/

配置服务器是一个基础设施组件,用于提供可能位于 git 存储库中的配置。

配置客户端应用程序会在启动时连接到 config-server 并加载适用于当前配置文件的配置。

您可以为不同的环境设置不同的分支,或者使用每个环境的配置文件。在您的 Kubernetes 部署清单中,您可以通过设置 SPRING_PROFILES_ACTIVE 环境变量来设置配置文件。


1
我们之前使用了Spring Cloud Config,现在想要切换到使用Kubernetes Configmap。你有什么想法如何使用Kubernetes Configmap实现类似的功能吗? - A V

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接