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

时间:2018-10-31 23:05:23

标签: kubernetes kubernetes-helm go-templates

我正在学习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文件的舵图为每个节点生成自定义配置文件。

有什么想法或建议吗?

2 个答案:

答案 0 :(得分:1)

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

Kubernetes文档的a fairly detailed of example of this面向复制的MySQL集群,但是具有相同的基本设置:有一个主节点和一些副本,每个副本都需要知道自己的ID,并且配置文件是在主数据库和副本数据库上有所不同。

您可以使用的重要细节似乎是:容器的hostname(如在shell命令中一样)为statefulsetname-123,其中数字是连续的,并且可以保证各个容器可以启动为了。 a `statefulset.kubernetes.io/pod-name' label中有相同的详细信息,您可以通过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,将其拆分为两个数字,然后将实际的配置文件写入临时卷。然后,主容器将共享的config目录安装到它希望其配置文件位于的任何位置。

答案 1 :(得分:0)

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 的同一命名空间中。

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