Last active
November 23, 2019 23:36
-
-
Save barnybug/6375322 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# Script to run dynamic dns for docker containers. | |
# DNS is served by dnsmasq running on the docker0 gateway ip, and dynamically | |
# updated at containers come and go. | |
# | |
# To use from docker, just provide the --dns option: | |
# docker run --dns <gateway> ... | |
# The gateway ip you need will be printed when this script is run. | |
import os | |
import logging | |
import json | |
import re | |
import select | |
import subprocess | |
import tempfile | |
def path(name): | |
for entry in os.getenv('PATH').split(':'): | |
fname = os.path.join(entry, name) | |
if os.path.exists(fname): | |
return fname | |
raise ValueError("Couldn't find %s on PATH" % (name)) | |
# Constants | |
DOCKERIFACE = 'docker0' | |
DNSMASQ = path('dnsmasq') | |
DOCKER = path('docker') | |
class Monitor(object): | |
def __init__(self): | |
(fd, self.hosts) = tempfile.mkstemp(suffix='.hosts') | |
self.gateway = self.get_iface_addr() | |
logging.info("Listening on %s" % self.gateway) | |
logging.info("You should run docker as: docker run --dns %s ..." % self.gateway) | |
self.events = None | |
os.chmod(self.hosts, 0644) | |
def get_iface_addr(self): | |
output = subprocess.check_output('ip addr show dev %s' % DOCKERIFACE, shell=True) | |
m = re.search(r'inet (\d+\.\d+\.\d+\.\d+)', output) | |
if not m: | |
raise ValueError("Unable to get docker ip address") | |
return m.group(1) | |
def get_docker_ids(self): | |
ids = [] | |
lines = subprocess.check_output('docker ps', shell=True).split('\n') | |
for line in lines[1:]: | |
if not line: | |
continue | |
id, image, command, created, status, ports = re.split('\s{2,}', line) | |
ids.append(id) | |
return ids | |
def build_hosts(self): | |
logging.info('Updating hosts file') | |
with file(self.hosts, 'w') as fout: | |
ids = self.get_docker_ids() | |
if not ids: | |
return None | |
data = subprocess.check_output('docker inspect %s' % ' '.join(ids), shell=True) | |
i = json.loads(data) | |
for container in i: | |
hostname = container['Config']['Hostname'] | |
ipaddress = container['NetworkSettings']['IPAddress'] | |
print >>fout, '%s %s' % (ipaddress, hostname) | |
logging.info('Found: %s %s' % (ipaddress, hostname)) | |
logging.info('Generated hosts file with %s entries: %s' % (len(i), self.hosts)) | |
def start_dnsmasq(self): | |
args = [DNSMASQ, '--addn-hosts', self.hosts, '--bind-interfaces', '--listen-address', self.gateway, '--keep-in-foreground'] | |
self.dnsmasq = subprocess.Popen(args) | |
logging.info("Started dnsmasq pid: %d" % self.dnsmasq.pid) | |
def stop_dnsmasq(self): | |
logging.info("Terminating dnsmasq pid: %d" % self.dnsmasq.pid) | |
self.dnsmasq.terminate() | |
def restart_dnsmasq(self): | |
self.stop_dnsmasq() | |
self.start_dnsmasq() | |
def tail_events(self): | |
if not self.events: | |
self.events = subprocess.Popen([DOCKER, 'events'], stdout=subprocess.PIPE) | |
logging.info('Tailing docker events...') | |
f = self.events.stdout | |
# wait on data | |
while select.select([f.fileno()], [], []): | |
data = f.readline() | |
event = data.strip().split()[-1] | |
logging.info('Received docker event: %s' % event) | |
if event in ('start', 'die'): | |
self.build_hosts() | |
self.restart_dnsmasq() | |
def run(self): | |
self.build_hosts() | |
self.start_dnsmasq() | |
self.tail_events() | |
if __name__=='__main__': | |
logging.basicConfig(level=logging.INFO, format='%(asctime)-15s %(message)s') | |
monitor = Monitor() | |
monitor.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment