Named after the cryptid Queensland Tiger.
Queensland is a simple, etcd backed DNS server. Other such servers tend to be rather "ambitious" while queensland is designed to be very simple.
Queensland supports basic service discovery via DNS using either A or SRV lookups.
Queensland also provides helpers for node and service announcement.
Queensland is still under heavy development.
Currently, only IPv4 addresses are supported.
go get github.com/mistifyio/queensland
Developed and tested with go 1.4
Queensland has three modes of operation:
- node - announce the node for basic resolution
- announce - announce a single service
- server - run the DNS server
running queensland help
will show command line options.
In node mode, queensland will announce the node. This simply means
that it will put an entry into etcd for the node to be used for base
DNS resolution. Running queensland node
will use the hostname and
attempt to find the ip address of the node. On my laptop, for
example, this will insert a record that can be retrieved like:
$ etcdctl get /queensland/nodes/helo
{"ip":"192.168.1.56"}
The node name and address can be set via the command line:
$ queensland help node
Usage:
queensland node [flags]
Available Flags:
-a, --address="": node addresses. will default to first non-localhost IP
-e, --etcd="http://127.0.0.1:4001": etcd endpoint
-h, --help=false: help for node
-i, --interval=300: announce interval
-n, --name="": node name. will default to hostname.
-p, --prefix="/queensland": etcd prefix
--remove=false: remove key on exit
-t, --ttl=0: announce ttl. 0 disables
In general, you would run this as a service on every node.
The record, by default, is not removed on exit, but relies on the
ttl. Using the --remove
flag will attempt to remove the key when the
process exits.
You could use etcdctl
or curl
to set the same data if desired. The
"node mode" is a convenience as it ensures proper namespacing and data
format.
Announce mode is used to announce a single instance of a service. It is generally ran on the same node as the service is running. It is usually ran as a "side-car" service.
Assuming I had a "www" service running on my laptop, I would run
queensland announce www
and this would insert a record that could be
fetched:
$ etcdctl get /queensland/services/www/helo
{"priority":0,"weight":0,"port":0,"target":"helo"}
The node name, etc, can be overridden on the command line:
$ queensland help announce
Available Flags:
-c, --check="": announce check command
-e, --etcd="http://127.0.0.1:4001": etcd endpoint
-h, --help=false: help for announce
-i, --interval=30: announce interval
-n, --name="": node name. will default to hostname.
-o, --port=0: announce service port
-p, --prefix="/queensland": etcd prefix
--remove=false: remove key on exit
-r, --priority=0: announce service priority
-t, --ttl=60: announce ttl. 0 disables
-w, --weight=0: announce service weight
A service announcement can optionally call a check command:
queensland announce www --check="curl http://127.0.0.1:8888/"
And it will only put the key when this command returns 0. The check command is ran using "sh -c".
The record, by default, is not removed on exit, but relies on the
ttl. Using the --remove
flag will attempt to remove the key when the
process exits.
You could use etcdctl
or curl
to set the same data if desired. The
"announce mode" is a convenience as it ensures proper namespacing and data
format.
In server mode, queensland runs a simple DNS server. Queensland can serve one and only one domain. It can serve services and nodes.
$ queensland help sever
Usage:
queensland server [flags]
Available Flags:
-d, --dns-port=15353: dns server port
-m, --domain=".local": dns domain
-e, --etcd="http://127.0.0.1:4001": etcd endpoint
-h, --help=false: help for server
-o, --http-port=25353: http server port
-p, --prefix="/queensland": etcd prefix
-t, --ttl=0: dns ttl
Using the above examples, we can lookup both the node and the service:
$ dig @127.0.0.1 -p 15353 helo.nodes.local +short
192.168.1.56
$ dig @127.0.0.1 -p 15353 www.services.local +short
192.168.1.56
$ dig @127.0.0.1 -p 15353 www.services.local +short SRV
0 0 0 helo.local.
$ dig @127.0.0.1 -p 15353 www.services.local SRV
;; ANSWER SECTION:
www.services.local. 0 IN SRV 0 0 0 helo.local.
;; ADDITIONAL SECTION:
helo.local. 0 IN A 192.168.1.56
Notice we can lookup the service using an A or an SRV lookup.
You can also do RFC 2782 style lookups for services:
$ dig @127.0.0.1 -p 15353 _www._tcp.services.local SRV
;; ANSWER SECTION:
www.services.local. 0 IN SRV 0 0 0 helo.local.
;; ADDITIONAL SECTION:
helo.local. 0 IN A 192.168.1.56
This only works for SRV lookups, not A. Also, the protocol must be
_udp
or _tcp
but it does not matter which.
You can also add external services:
$ etcdctl set /queensland/services/www/external '{"target": "some.other.domain.","port": 80 }'`
$ dig @127.0.0.1 -p 15353 www.services.local SRV
;; ANSWER SECTION:
www.services.local. 0 IN SRV 0 0 0 helo.local.
www.services.local. 0 IN SRV 0 0 80 some.other.domain.
;; ADDITIONAL SECTION:
helo.local. 0 IN A 192.168.1.56
You should run a "real" name server in front of queensland and only forward the service discover names to it. You can set a ttl great than 0 if you want it to be cached.
While it works, it is not very well tested.
- add metrics, etc
- remove records on exit?
- General code clean-up
- template for check command to use Port, name, address, etc?
An example of a node using systemd.
Run the node announce mode on every node:
# /etc/systemd/system/node-announce.service
[Unit]
Description=Queensland Node Announce
[Service]
ExecStart=/usr/sbin/queensland node
User=nobody
RestartSec=30s
Restart=always
[Install]
WantedBy=multi-user.target
Suppose we have an app like:
# /etc/systemd/system/myapp.service
[Unit]
Description=My App
Wants=myapp-announce.service
[Service]
ExecStart=/opt/myapp/bin/myapp
[Install]
WantedBy=multi-user.target
Notice the Wants=myapp-announce
And now the service announcement:
# /etc/systemd/system/myapp-announce.service
[Unit]
Description=Queensland Announce MyApp
BindsTo=myapp.service
[Service]
ExecStart=/usr/sbin/queensland announce myapp --port 8080 --check "curl http://127.0.0.1:8080/test"
User=nobody
RestartSec=30s
Restart=always
Notice the BindsTo=myapp.service