6

困境:使用相同的 docker 映像和代码部署多个应用程序和数据库容器对,但配置不同(使用子域的不同客户端)。

有什么合乎逻辑的方法来解决这个问题,因为 kubernetes 似乎没有支持这种设置的集成?

可能的方法

  1. 对所有应用部署使用单一应用服务,对所有数据库部署使用单一数据库服务。运行单个 Nginx 静态文件服务和部署,它将从在应用程序部署之间共享的静态卷中提供静态文件(都使用同一组静态文件)。每当需要新的部署时,让 bash 脚本复制应用程序和数据库的 .yaml 部署文件,并将 sed 文本替换为客户端的名称,并指向正确的 configmap(当然是手动编写的)并 kubectl 应用它们。一个主要的 nginx 入口将处理传入的流量并通过应用程序部署服务指向正确的 pod
  2. 与上面类似,除了使用 StatefulSet 而不是单独的部署,以及使用 init 容器将不同的配置复制到挂载的卷(唯一的缺点是您不能删除 statefulset 中间的项目,如果您不再需要,就会出现这种情况客户端的特定容器,这似乎是一种非常hacky的方法)。

理想情况下,如果 StatefulSet 可以使用向下 api 根据可以解决问题的有状态集的索引动态选择配置映射名称(您基本上可以使用名称中的索引手动制作配置文件,并且它将被选中适当)。就像是:

env:
- name: POD_NAME
  valueFrom:
    fieldRef:
      fieldPath: metadata.name

envFrom:
- configMapRef:
  name: $(POD_NAME)-config

但是,kubernetes 中没有该功能。

4

3 回答 3

2

Helm这样的模板引擎可以帮助解决这个问题。(我相信当前Kubernetes附带的 Kustomize 也可以做到这一点,但我对 Helm 更熟悉。)基本思想是你有一个包含 Kubernetes YAML 文件但可以使用模板语言(the Go text/templatelibrary) 来动态填写内容。

在这个设置中,通常你会让 Helm 同时创建 ConfigMap 和匹配的 Deployment;在您描述的设置中,您将为每个租户单独安装它(Helm版本)。假设 Nginx 配置足够不同,以至于您想将它们存储在外部文件中;图表的核心部分将包括

values.yaml(可覆盖的配置,helm install --set nginxConfig=bar.conf):

# nginxConfig specifies the name of the Nginx configuration
# file to embed.
nginxConfig: foo.conf

模板/configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-{{ .Chart.Name }}-config
data:
  nginx.conf: |-
{{ .Files.Get .Values.nginxConfig | indent 4 }}

部署.yaml

apiVersion: v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-{{ .Chart.Name }}-nginx
spec:
  ...
    volumes:
      - name: nginx-config
        configMap:
          name: {{ .Release.Name }}-{{ .Chart.Name }}-config

{{ .Release.Name }}-{{ .Chart.Name }}是一个典型的约定,允许在同一个命名空间中安装图表的多个副本;第一部分是您给helm install命令的名称,第二部分是图表本身的名称。您也可以直接指定 ConfigMap 的内容,.Values...从文件中引用其他设置values.yaml,使用 ConfigMap 作为环境变量而不是文件,等等。

于 2020-01-23T10:43:46.757 回答
1

虽然动态结构替换是不可能的(正负,整个故事见下文),我相信你的initContainer:想法是正确的;您可以使用来从 API 中serviceAccount获取,然后在主容器启动时获取该环境:configMapinitContainer:

initContainers:
- command:
  - /bin/bash
  - -ec
  - |
       curl -o /whatever/env.sh \
       -H "Authorization: Bearer $(cat /var/run/secret/etc/etc)" \
       https://${KUBERNETES_SERVICE_HOST}/api/v1/namespaces/${POD_NS}/configmaps/${POD_NAME}-config
  volumeMounts:
  - name: cfg  # etc etc
containers:
- command:
  - /bin/bash
  - -ec
  - "source /whatever/env.sh; exec /usr/bin/my-program"
  volumeMounts:
  - name: cfg  # etc etc
volumes:
- name: cfg
  emptyDir: {}

在这里,我们有fetchingConfigMap与.PodSpecConfigMap


一个单独的、更复杂(但可能很优雅)的方法是Mutating Admission Webhook,看起来他们甚至最近使用Pod Presets正式化了你的用例,但从文档中并不清楚哪个版本功能第一次出现,也没有任何 apiserver 标志,必须旋转才能利用它。

于 2020-01-23T08:27:50.533 回答
0

PodPresets 自 v1.20 以来已被删除,基于 Mutating Admission Webhook 的更优雅的解决方案现已提供https://github.com/spoditor/spoditor

PodSpec本质上,它在模板上使用自定义注释,例如:

      annotations:
        spoditor.io/mount-volume: |
          {
            "volumes": [
              {
                "name": "my-volume",
                "secret": {
                  "secretName": "my-secret"
                }
              }
            ],
            "containers": [
              {
                "name": "nginx",
                "volumeMounts": [
                  {
                    "name": "my-volume",
                    "mountPath": "/etc/secrets/my-volume"
                  }
                ]
              }
            ]
          }

现在,nginxStatefulSet 的每个 Pod 中的容器都会尝试以my-secret-{pod ordinal}.

您只需要确保StatefulSet 的同一个命名空间中存在my-secret-0, my-secret-1, 等等。

项目文档中有更高级的注释用法。

于 2021-04-16T21:10:33.320 回答