/dev/blog/ID10T

Simplifying cloud-config creation for clusters

• coreos and cloud • Comments
Advertisement

I’m still experimenting with container orchestration. Currently I’m in the process of building a three node CoreOS cluster with Kubernetes on top of it, connected over the Internet. One problem I was constantly struggling with was keeping my cloud-configs in sync. Most of the configuration settings were identical or nearly identical on all three nodes. Still, when adding a small change, I needed to apply this change to all three files. Forgetting one or mistyping led to errors and unnecessary debugging sessions.

This weekend I decided I’ve had enough of it. I created a small Python script to simplify working on several nearly identical configuration files, cloud-config-creator. By iterating over a set of node values and one master template the script creates the cloud-configs for all nodes. It’s little more than a wrapper for the Jinja2 templating engine, but I still find this incredibly useful. That’s why I want to add a bit more explanation around it.

Prerequisites

You will need Python. I used Python 3, never tested it with 2.x. Furthermore you need to install the pyyaml and jinja2 modules. Before starting to use cloud-config-creator you should have basic knowledge of how to use templates. If you ever worked with a templating engine (e.g. for consul-template or Jekyll), you’ll quickly feel at home. Otherwise I recommend the Jinja2 documentation.
Furthermore you should know how to format YAML. My script uses PyYAML, which isn’t YAML 1.2 compatible (yet), so you’ll need to use YAML 1.1.

Script usage

./cloud-config --templatefile master.tmpl --valuesfile values.yml --outpath out/ --includepath includes/
Advertisement

Template Examples

Basic

Lets start with a very simple (and unrealistic) example. You only want to have the hostname of every node set into the cloud-config.

The master template would look like that:

#cloud-config
hostname: {{ my.hostname}}

The values file would be straightforward as well:

-
  hostname: node1.adminswerk.de
-
  hostname: node2.adminswerk.de
-
  hostname: node3.adminswerk.de

To be consistent between files, the values file is YAML, just like the template.

Running the script is easy as well:

./cloud-config-creator.py --templatefile ~/coreos/master.tmpl --valuesfile ~/coreos/values.yml

This would create three files in the current directory named nodeX.adminswerk.de.yml, which could then be deployed to the CoreOS nodes. Note how all values of the current node are called via my.*.

Advanced

Now we’ll add an etcd2 cluster to the cloud-config. I prefer to have the current node as first one in all endpoint lists (although I’m pretty sure this has no effect on actual endpoint selection). Here’s the excerpt from the master template:

coreos:
  etcd2:
    name: "{{ my.etcd.nodename }}"
    data-dir: /var/lib/etcd2
    # clients
    advertise-client-urls: https://{{ my.network.ip }}:2379
    listen-client-urls: https://0.0.0.0:2379
    # peers
    initial-advertise-peer-urls: https://{{ my.network.ip }}:2380
    listen-peer-urls: https://{{ my.network.ip }}:2380
    # cluster
    initial-cluster: {{ my.etcd.nodename }}=https://{{ my.network.ip }}:2380,{% for node in remaining_nodes %}{{ node.etcd.nodename }}=https://{{ node.network.ip }}:2380
            {%- if not loop.last %},{% endif %}{% endfor %}
    initial-cluster-state: new
    initial-cluster-token: etcd-cluster-1

The values file now looks like this:

-
  hostname: node1.adminswerk.de
  network:
    ip: 172.13.37.100
  etcd:
    nodename: node1
-
  hostname: node2.adminswerk.de
  network:
    ip: 172.13.37.101
  etcd:
    nodename: node2
-
  hostname: node3.adminswerk.de
  network:
    ip: 172.13.37.102
  etcd:
    nodename: node3

Here, the initial-cluster uses a for-loop. The used variable remaining_nodes is self-explanatory, it contains all notes except the current which as already explained can be called via my.*. If you just wanted to iterate over all nodes, you could use the nodes variable for that.
Also this line uses some whitespace control to stretch out the templating code for an easier overview and an additional if-clause to prevent a comma after the last node.

If you want to see a more complete example, take a look into the master-example.tmpl and values-example.yaml in the scripts repository.

I will probably distribute more examples in the future, as I plan to publish the templates I’m creating during my experiments.

Advertisement
More posts
comments powered by isso

Advertisement