Service discovery and hot reconfiguration is a common problem we face in cloud development nowadays. In some cases we can rely on an orchestration engine like Kubernetes to do all the work for us. In other cases we can leverage a configuration management system and do the orchestration ourselves. However, there are still some cases where either of these solutions are impractical or just too complex for the immediate problem… and you don’t have a Consul cluster at hand either :(.
confd to the rescue
Confd is a Golang written binary that allows us to make configuration files dynamic by providing a templating engine driven by backend data stores like etcd, Consul, DynamoDb, Redis, Vault, Zookeeper. It is commonly used to allow classic load balancers like Nginx and HAProxy to automatically reconfigure themselves when new healthy upstream services come online under different IP addresses.
NOTE: For the sake of simplicity I will use a very simple example to demonstrate how to use confd to remotely reconfigure an Nginx route by listening to changes performed against an Azure Redis Cache backend. However, this idea can be extrapolated to solve service discovery problems whereby application instances continuously report their health and location to a Service Registry (in our case Azure Redis) that is monitored by the Load Balancer service in order to reconfigure itself if necessary.
Just as a side note, confd was created by Kelsey Hightower (now Staff Developer Advocate, Google Cloud Platform) in the early Docker and CoreOS days. If you haven’t heard of Kelsey I totally recommend you YouTube around for him to watch any of his talks.
Azure Redis Cache
Redis, our Service Discovery data store will be listening on XXXX-XXXX-XXXX.redis.cache.windows.net:6380 (whereXXXX-XXXX-XXXX is your DNS prefix). confd will monitor changes on the
/myapp/suggestions/drink cache key and then update Nginx configuration accordingly.
confd + nginx container image
confd’s support for Redis backend using a password is still not available under the stable or alpha release as of August 2017. I explain how to easily compile the binary and include it in an Nginx container in a previous post.
docker pull xynova/nginx-confd
socat container image
confd is currently unable to connect to Redis through TLS (required by Azure Redis Cache). To overcome this limitation we will use a protocol translation tool called socat which I also talk about in a previous post.
docker pull xynova/socat
Preparing confd templates
Driving Nginx configuration with Azure Redis
We first start a
xynova/nginx-confd container and mount our prepared confd configurations as a volume under the
/etc/confd path. We are also binding port 80 to 8080 on localhost so that we can access Nginx by browsing to http://localhost:8080.
To fix this we bring
xynova/socat to create a tunnel that confd can use to talk to Azure Redis Cache in the cloud. We open a new terminal and type the following (note: replace XXXX-XXXX-XXXX with your own Azure Redis prefix).
Notice that by specifying
--net container:nginx option, I am instructing the
xynova/socat container to join the
xynova/nginx-confd container network namespace. This is the way we get containers to share their own private localhost sandbox.
Now looking back at our interactive logs we can see that confd is now talking to Azure Redis but it cannot find the
/myapp/suggestions/drink cache key.
Lets just set a value for that key:
confd is now happily synchronized with Azure Redis and the Nginx service is up and running.
We now browse to http://localhost:8080 and check test our container composition:
Covfefe… should we fix that?
We just set the
/myapp/suggestions/drink key to
Watch how confd notices the change and proceeds to update the target config files.
Now if we refresh our browser we see: