Beruflich Dokumente
Kultur Dokumente
Please exit printing, wait for images to load, and try to
Michael S. Fischer Follow
print again.
Principal Engineer, DevOps + SRE. Erstwhile attorney.
Mar 3, 2017 · 9 min read
Making Docker and Consul Get Along
If you manage the technology stack for an Internet business of any
signi cant size, you’ve probably heard of Consul. Consul is a fantastic
solution for providing, among other things, powerful and reliable
service-discovery capability to your network. It’s not surprising that
you’d want to use it.
Summary
• Install Consul and dnsmasq either directly on your host, or in a
container using host networking ( --net=host ).
• Con gure Consul to bind its HTTP and client RPC services to the
dummy network interface’s IP address.
Consul and Containerized Applications
Suppose you’ve determined that you want to use Consul on your
Docker host, and you have the following requirements:
Installing Consul on your Docker Host
It’s considered a best practice to install and run the Consul Agent on
every host in your network, including your Docker hosts. This has a few
important bene ts:
The most controversial question is, should you install the Consul
Agent directly on the host, or install it in a container?
The answer is: it doesn’t matter — but the network con guration
does. Consul itself is a small, self-contained Linux binary; it has no
dependencies. You can certainly run it as a container if you wish, but
the bene t of runtime environment isolation that makes containers so
appealing is minimal when the application doesn’t need isolation
anyway. My personal preference is to run Consul as a rst-class service
on the host, alongside essential system services as the Docker engine
and sshd daemon.
Consul and the Loopback Interface
When you run the Consul agent, it listens on six ports, all of which
serve di erent functions. The three ports essential to our discussion
are:
• HTTP API (default: 8500): handles HTTP API requests from clients
Ideas we considered, but rejected
• Con guring Consul to bind to all interfaces. That would make the
HTTP and CLI RPC ports open to the world unless we also craft
iptables(8) rules to block requests from foreign hosts. In
addition, we’d have to ensure the containers know the IP address
of the host they’re running on in order to communicate with its
Consul agent.
• Con guring Consul to bind to the Docker bridge IP address. The
routing would work properly, but: (a) typically, bridge interfaces
are assigned dynamically by Docker; (b) there may be more than
one bridge interface; (c) containers would have to know the IP
address of the selected bridge interface; and (d) the Consul agent
and dnsmasq (discussed below) would not be able to start until
the Docker engine has started. We don’t want to create any
unnecessary dependencies.
The Dummy Interface Solution
Linux provides a little-known network interface type called a “dummy
interface.” It’s much like a loopback interface, but you can give it any IP
address you like, and you can create as many of them as you like (but
we only need one). Here’s an example:
Every host can use the same 169.254.1.1 address with its dummy
interface. This makes con guration a lot easier, since you don’t have to
write scripts to determine the IP address and provide it to the programs
that need it.
Con guring the interface
If your Linux distribution uses systemd , it’s easy to set up the dummy
interface at boot time by creating two les. (You may need to install
systemd-networkd via your distribution’s package manager, enable it,
and start it.)
[NetDev]
Name=dummy0
Kind=dummy
[Match]
Name=dummy0
[Network]
Address=169.254.1.1/32
Run sudo systemctl restart systemd-networkd and your new dummy0
Con guring Consul to use the dummy interface
Next, let’s con gure the Consul agent to bind its HTTP, CLI RPC, and
DNS interfaces to the 169.254.1.1 address.
with the following content, substituting your host’s IP address for the
value of HOST_IP_ADDRESS below.
{
"client_addr": "169.254.1.1",
"bind_addr": "HOST_IP_ADDRESS"
}
Con guring dnsmasq to use the dummy interface
dnsmasq is a fantastic piece of software. Among other things, it can act
as a local DNS cache on your host. It’s extremely exible and can make
integration with Consul’s DNS service a snap. We’re going to install it
on our server; bind it to both our loopback and dummy interfaces;
make it pass queries ending in .consul to the Consul agent; and
con gure /etc/resolv.conf on both the host and our containers to
dispatch DNS queries to it.
server=/consul/169.254.1.1#8600
listen-address=127.0.0.1
listen-address=169.254.1.1
Then restart dnsmasq.
Putting it together: Containers, Consul,
and DNS
The key to making everything work at this point is to ensure that the
container itself, and the code running inside, point to the right address
when resolving DNS queries or connecting to Consul’s HTTP API.
When starting your Docker container, con gure it so that it uses the
dnsmasq server as its resolver:
How about Consul API access? The key is to set two standard
environment variables called CONSUL_HTTP_ADDR and
CONSUL_RPC_ADDR . Nearly all standard Consul client libraries use these
values to determine where to send queries. Be certain your code uses
these variables too — never hard-code Consul endpoints into your
applications!
# curl http://$CONSUL_HTTP_ADDR/v1/catalog/service/myapp?
pretty
[
{
"ID": "6c542e7f-a68d-4de0-bcc0-7eb6b80b68e3",
"Node": "vessel",
"Address": "10.0.0.2",
"ServiceID": "myapp",
"ServiceName": "myapp",
"ServiceTags": [],
"ServiceAddress": "",
"ServicePort": 80,
"ServiceEnableTagOverride": false,
"CreateIndex": 60,
"ModifyIndex": 60
}
]
# /etc/environment
CONSUL_HTTP_ADDR=169.254.1.1:8500
CONSUL_RPC_ADDR=169.254.1.1:8400
Registering your containers
Now that we’ve shown that containers can access the Consul agent,
you’ll want to publish their services into the Consul catalog.
There are many tools and options for doing so. My favorite open-source
tool for this task is Registrator, which is available from Docker Hub.
Registrator will notice, and publish to Consul. (Since the nginx image
exposes two ports, Registrator will append -80 and -443 to the
webservice service name when registering it with the catalog. You can
change that behavior if you like by setting other environment
variables.)
$ curl
http://$CONSUL_HTTP_ADDR/v1/catalog/service/webservice-80?
pretty
[
{
"ID": "6c542e7f-a68d-4de0-bcc0-7eb6b80b68e3",
"Node": "vessel",
"Address": "10.0.0.2",
"ServiceID": "vessel:webservice:80",
"ServiceName": "webservice-80",
"ServiceTags": [],
"ServiceAddress": "",
"ServicePort": 32772,
"ServiceEnableTagOverride": false,
"CreateIndex": 496,
"ModifyIndex": 496
}
]
Conclusion
With clever use of dummy network interfaces, we can allow Docker
hosts to utilize a Consul agent without any di cult or confusing
con guration.
And with Registrator, we can easily publish running Docker containers
to Consul with minimal e ort.