使用 Kubernetes 和 Helm 进行配置管理
Configuration management with Kubernetes and Helm
我是 Kubernetes 和 Helm 的新手。我来自平凡的Docker/docker-compose世界
我有一些复杂的服务 运行 多个 Docker 需要大量配置参数和逻辑的容器。 docker 化的服务在启动时需要大量不同的配置文件、密钥和命令行参数。我还需要一些只能在容器内部执行的运行时配置逻辑(必须生成一些配置元素)。
我最后做的是编写一个 shell 脚本(用作 CMD
),它需要环境变量,定义默认值,将这些环境变量转换为命令参数和配置文件。
这是我如何构建它的一个非工作示例,没有考虑 Kubernetes 和 Helm。
Docker文件
...
CMD [ "./bootstrap.sh" ]
bootstrap.sh(打包在图片中)
# Define default values, if no environment variables provided on
# on "docker run"
export CONFIG_VALUE_A=${CONFIG_VALUE_A:="a"}
export CONFIG_VALUE_B=${CONFIG_VALUE_B:="b"}
export CONFIG_VALUE_C=${CONFIG_VALUE_C:="c"}
# write CONFIG_VALUE_A to file
echo ${CONFIG_VALUE_A} > ./some-config-file-a.cfg
ARGS="--config-file-a ./some-config-file-a.cfg --config-value-b ${CONFIG_VALUE_B} --config-value-c ${CONFIG_VALUE_C}"
exec ./my-app ${ARGS}
这样的好处是使用环境变量,我有一个标准的配置界面,不需要处理配置文件的卷。
现在,我正在使用 Helm 进入 Kubernetes。 Helm 使用 values.yaml
有自己的参数概念。为了将它与我上面已经拥有的结合起来,我只需要将 values.yaml
中的值与那些环境变量进行映射。
deployment.yaml
...
spec:
...
template:
...
spec:
containers:
- name: my-app
...
env:
- name: "CONFIG_VALUE_A"
value: {{ .Values.config.value_a }}
- name: "CONFIG_VALUE_B"
value: {{ .Values.config.value_b }}
- name: "CONFIG_VALUE_C"
value: {{ .Values.config.value_c }}
values.yaml
config:
value_a: a
value_b: b
value_c: c
但是,我在其中来回映射值的三个配置层(helm 模板 => 容器环境变量 => 配置 files/CLI 参数)违反了 DRY 原则,并为 [=70 增加了很多潜力=] 以后就很难找到了。
理想情况下,
- 我只想在
deployment.yaml
中定义我的配置结构,在 Helm 的 default.yaml
中定义我的默认值
- 我会将这些值直接传递给容器,让某种配置脚本构建命令行参数和配置文件,而不使用环境变量作为中间层
- 使用某种类型安全的配置格式
- 尽可能减少总行数
- 保持配置文件的可读性,不要混淆不同的语言(即 JSON 在 YAML 文件中定义)
如何使用 Kubernetes、Helm 和 Docker 解决复杂的配置管理问题?
在Kubernetes世界中,configs通常由ConfigMap来管理,ConfigMap是配置的主要存储。
你的情况,我觉得你可以那样做(至少我会做,我会那样做):
- 在 Helm 中使用种类 ConfigMap 创建另一个模板,并在那里为应用程序创建一个
.cfg
文件结构。 Helm 使用 GoTemplate 格式,因此很容易在那里创建任何结构,包括迭代等。
- 将所有默认值添加到
values.yaml
文件。
- 编辑
deployment.yaml
。将 .cfg
文件的挂载添加到容器中的路径并将应用程序指向它。
- 使用带有值的附加文件(或多次)并将默认值的覆盖写入其中。
所以,就是这样。我们有:
- 应用格式的静态配置的ConfigMap,我们可以随时查看。
- 只有一个地方我们可以对其进行编辑 - 在我们的默认设置中并覆盖 yamls。
- 可读
key: value
YAML 格式。
- 配置文件生成和排序的所有逻辑都在一个容器中,所以我们不需要为了改变选项的顺序而构建一个新版本。
我是 Kubernetes 和 Helm 的新手。我来自平凡的Docker/docker-compose世界
我有一些复杂的服务 运行 多个 Docker 需要大量配置参数和逻辑的容器。 docker 化的服务在启动时需要大量不同的配置文件、密钥和命令行参数。我还需要一些只能在容器内部执行的运行时配置逻辑(必须生成一些配置元素)。
我最后做的是编写一个 shell 脚本(用作 CMD
),它需要环境变量,定义默认值,将这些环境变量转换为命令参数和配置文件。
这是我如何构建它的一个非工作示例,没有考虑 Kubernetes 和 Helm。
Docker文件
...
CMD [ "./bootstrap.sh" ]
bootstrap.sh(打包在图片中)
# Define default values, if no environment variables provided on
# on "docker run"
export CONFIG_VALUE_A=${CONFIG_VALUE_A:="a"}
export CONFIG_VALUE_B=${CONFIG_VALUE_B:="b"}
export CONFIG_VALUE_C=${CONFIG_VALUE_C:="c"}
# write CONFIG_VALUE_A to file
echo ${CONFIG_VALUE_A} > ./some-config-file-a.cfg
ARGS="--config-file-a ./some-config-file-a.cfg --config-value-b ${CONFIG_VALUE_B} --config-value-c ${CONFIG_VALUE_C}"
exec ./my-app ${ARGS}
这样的好处是使用环境变量,我有一个标准的配置界面,不需要处理配置文件的卷。
现在,我正在使用 Helm 进入 Kubernetes。 Helm 使用 values.yaml
有自己的参数概念。为了将它与我上面已经拥有的结合起来,我只需要将 values.yaml
中的值与那些环境变量进行映射。
deployment.yaml
...
spec:
...
template:
...
spec:
containers:
- name: my-app
...
env:
- name: "CONFIG_VALUE_A"
value: {{ .Values.config.value_a }}
- name: "CONFIG_VALUE_B"
value: {{ .Values.config.value_b }}
- name: "CONFIG_VALUE_C"
value: {{ .Values.config.value_c }}
values.yaml
config:
value_a: a
value_b: b
value_c: c
但是,我在其中来回映射值的三个配置层(helm 模板 => 容器环境变量 => 配置 files/CLI 参数)违反了 DRY 原则,并为 [=70 增加了很多潜力=] 以后就很难找到了。
理想情况下,
- 我只想在
deployment.yaml
中定义我的配置结构,在 Helm 的default.yaml
中定义我的默认值
- 我会将这些值直接传递给容器,让某种配置脚本构建命令行参数和配置文件,而不使用环境变量作为中间层
- 使用某种类型安全的配置格式
- 尽可能减少总行数
- 保持配置文件的可读性,不要混淆不同的语言(即 JSON 在 YAML 文件中定义)
如何使用 Kubernetes、Helm 和 Docker 解决复杂的配置管理问题?
在Kubernetes世界中,configs通常由ConfigMap来管理,ConfigMap是配置的主要存储。
你的情况,我觉得你可以那样做(至少我会做,我会那样做):
- 在 Helm 中使用种类 ConfigMap 创建另一个模板,并在那里为应用程序创建一个
.cfg
文件结构。 Helm 使用 GoTemplate 格式,因此很容易在那里创建任何结构,包括迭代等。 - 将所有默认值添加到
values.yaml
文件。 - 编辑
deployment.yaml
。将.cfg
文件的挂载添加到容器中的路径并将应用程序指向它。 - 使用带有值的附加文件(或多次)并将默认值的覆盖写入其中。
所以,就是这样。我们有:
- 应用格式的静态配置的ConfigMap,我们可以随时查看。
- 只有一个地方我们可以对其进行编辑 - 在我们的默认设置中并覆盖 yamls。
- 可读
key: value
YAML 格式。 - 配置文件生成和排序的所有逻辑都在一个容器中,所以我们不需要为了改变选项的顺序而构建一个新版本。