如何为多个主机生成唯一的配置文件?

How to generate unique config files for multiple hosts?

我正在学习 k8s,并且正在努力编写 Helm 图表来为我用来提升生态系统的应用程序生成配置文件。我遇到了一个有趣的问题,我需要生成对所有节点通用的配置,以及一些对每个节点唯一的配置。知道我该怎么做吗?

来自我的 values.xml 文件:

# number of nodes / replicas
nodeCount: 5
replicaCount: 3

跨所有节点的通用配置称为 node_map.xml:

              <default>
                    <node>
                        <replica>
                            <host>wild-wallaby-0</host>
                            <port>8000</port>
                        </replica>
                        <replica>
                            <host>scary-rapids-1</host>
                            <port>8000</port>
                        </replica>
                    </node>
                    <node>
                        <replica>
                            <host>wild-wallaby-1</host>
                            <port>8000</port>
                        </replica>
                        <replica>
                            <host>scary-rapids-2</host>
                            <port>8000</port>
                        </replica>
                    </node>
                    <node>
                        <replica>
                            <host>wild-wallaby-2</host>
                            <port>8000</port>
                        </replica>
                        <replica>
                            <host>scary-rapids-0</host>
                            <port>8000</port>
                        </replica>
                    </node>
              </default>

上面的内容很容易生成,并且这个配置已经准备好用于作为单个容器的每个 pod,但是现在每个 pod 还需要编写一个额外的配置文件,让该 pod 知道该实例的节点和副本是,叫做instance.xml。请注意,该文件不需要被称为 instance.xml...只要我知道在启动命令中包含什么名称,我就可以灵活地指向并加载任何命名文件。

例如...

两个实例将 运行 在节点 wild-wallaby-0、节点 0 副本 1 和节点 0 副本 2 上。每个实例都需要这样生成的配置文件:

一审...

    <!-- node 0 replica 1 instance.xml -->
    <id>
        <node>0</node>
        <replica>1</replica>
    </id>

而第二个实例...

<!-- node 0 replica 2 instance.xml -->
    <id>
        <node>0</node>
        <replica>2</replica>
    </id>

这当然可以根据我的值文件中定义的节点和副本数遵循一些约定。虽然生成所有节点通用的文件很容易,但我不清楚如何从 instance.xml 文件的 helm 图表为每个节点生成自定义配置文件。

有什么想法或建议吗?

您可以将其部署为 StatefulSet,并使用 initContainers: 在 pod 的主要任务真正启动之前创建配置文件。

Kubernetes 文档 a fairly detailed of example of this 围绕一个复制的 MySQL 集群,但具有相同的基本设置:有一个主节点和一定数量的副本,每个都需要知道自己的 ID ,配置文件在主服务器和副本服务器上不同。

看起来您可以使用的重要细节是 pod 的 hostname(如在 shell 命令中)是 statefulsetname-123,其中数字是连续的,并且个人pods保证按顺序启动。 a `statefulset.kubernetes.io/pod-name' label, which you can retrieve via the downward API.

中有相同的详细信息

我可能会像这样创建一个 ConfigMap:

version: v1
kind: ConfigMap
metadata:
  name: config-templates
data:
  config.xml.tmpl: >-
    <id>
      <node>NODE</node>
      <replica>REPLICA</replica>
    </id>

然后我的 StatefulSet 规范部分看起来像:

version: apps/v1
kind: StatefulSet
...
spec:
  ...
  template:
    spec:
      volumes:
        - name: config
          emptyDir: {}
        - name: templates
          configMap:
            name: config-templates
      initContainers:
        - name: configfiles
          image: ubuntu:16.04
          command:
            - sh
            - -c
            - |
              POD_NUMBER=$(hostname | sed 's/.*-//')
              NODE=$(( $POD_NUMBER / 5 ))
              REPLICA=$(( $POD_NUMBER % 5 ))
              sed -e "s/NODE/$NODE/g" -e "s/REPLICA/$REPLICA/g" \
                /templates/config.xml.tmpl > /config/config.xml
          volumeMounts:
            - name: templates
              mountPath: /templates
            - name: config
              mountPath: /config
      containers:
        - name: ...
          ...
          volumeMounts:
            - name: config
              mountPath: /opt/myapp/etc/config

在该设置中,您要求 Kubernetes 创建一个在容器之间共享的空临时卷 (config),并将配置映射也作为一个卷提供。 init 容器提取顺序 pod ID,将其拆分为两个数字,并将实际配置文件写入临时卷。然后主容器将共享配置目录挂载到它期望其配置文件所在的任何位置。

https://github.com/spoditor/spoditor 就是为了用 StatefulSet 解决这个问题。它允许您将专用 configmapsecret 挂载到 StatefulSet 中的单个 Pod。

本质上,它在 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"
                  }
                ]
              }
            ]
          }

现在,StatefulSet 的每个 Pod 中的 nginx 容器将尝试以 my-secret-{pod ordinal}.

的模式挂载其自己的专用密钥

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

项目文档中有更多关于注解的高级用法。