Discovering etcd from inside a container in CoreOS

In this quick post, I show how you can discover the etcd endpoint from within a container running on CoreOS.

Reading and writing to etcd within a CoreOS is straightforward – you can use the etcdctl utility or just use regular HTTP to http://127.0.0.1:4001/v2/keys

But what about inside a container?

The CoreOS manual tells you you how to obtain the address of the docker0 interface on the host, but you still have to figure out how to get that into your container.

Here’s two alternatives you can try

Pulling the etcd endpoint from inside the container

Inside the container, you can use the address of the default gateway, as this will correspond with the docker0 interface on the host.

You could use a bash startup script for your service which uses a bit of grep and awk to build the endpoint, for example:

#!/bin/bash
ETCD_ENDPOINT=$(route|grep default|awk '{print $2}'):4001

So this is nice, but unsatisying. It’s not really finding where etcd is, it’s just exploiting a side effect of how CoreOS sets things up.

Pushing the etcd endpoint into the container

Here’s my current favourite method – we make the etcd service on the host write an environment file we can incorporate into our fleet units. To do that, we need to create a new file /run/systemd/system/etcd.service.d/30-environment.conf containing this

[Service]
#write an environment file to use in other units
ExecStartPost=/bin/bash -c "echo ETCD_ENDPOINT=${ETCD_ADDR} > /etc/etcd.environment"

You can write this file by hand and then have it take effect with

sudo systemctl daemon-reload
sudo systemctl restart etcd.service

You should see it created /etc/etcd.environment and we can include that in any fleet unit with Environment=/etc/etcd.environment, and from there it’s easy to use the ETCD_ENDPOINT variable to configure services.

This configuration isn’t permanent, we’ll lose it the next time CoreOS updates itself. You’ll need to have your provisioning system deploy it for you. Alternatively you can include a little extra bit into your cloud-config to create the file on newly minted or updated machines. Something like this would do the trick:

write_files:
- path: /run/systemd/system/etcd.service.d/30-environment.conf
  permissions: 420
  content: |
    [Service]
    #write an environment file to use in other units
    ExecStartPost=/bin/bash -c "echo ETCD_ENDPOINT=${ETCD_ADDR} > /etc/etcd.environment"

Summary

I’ve tried to show how a container can discover the etcd endpoint. The first method is fine, but I’d prefer something that wasn’t looking for a side effect, and was unequivocally told where etcd can be found. The second method does this, but is admittedly a bit more involved. I’d like to see CoreOS incorporate something like this themselves.

Hope this helps someone in the meantime!