Converted into a docker container

This commit is contained in:
Joachim Lusiardi 2015-01-22 11:04:17 +01:00
parent c02f5ea21e
commit 79b6019152
4 changed files with 153 additions and 97 deletions

21
Dockerfile Normal file
View File

@ -0,0 +1,21 @@
FROM debian:8
MAINTAINER Joachim Lusiardi
RUN apt-get update;
RUN apt-get install -y python3-pip
RUN apt-get install -y nginx
ADD nginx.conf /etc/nginx.conf
ADD start.sh /start.sh
RUN chmod +x /start.sh
ADD nginx_proxy.py /nginx_proxy.py
RUN chmod +x /nginx_proxy.py
RUN pip3 install docker-py
VOLUME ["/keys"]
EXPOSE 80
ENTRYPOINT /start.sh

18
nginx.conf Normal file
View File

@ -0,0 +1,18 @@
worker_processes 1;
events {
worker_connections 1024;
}
http {
sendfile on;
keepalive_timeout 65;
log_format https_combined '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" HTTPS';
log_format http_combined '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" HTTP';
include /tmp/nginx/*;
}
daemon on;
error_log /dev/stdout info;

View File

@ -1,27 +1,32 @@
#!/usr/bin/python3.4 #!/usr/bin/python3.4
import os from docker import Client
import sys from docker.errors import APIError
import http.client
import json
import signal
from string import Template from string import Template
import json
import datetime
import signal
import os
import logging
import sys
target_path="/tmp/nginx" target_path="/tmp/nginx/"
pid_file="/run/nginx.pid" pid_file="/var/run/nginx.pid"
non_location_template = """server { non_location_template = """# proxy for container '$containername'
server {
listen $listen; listen $listen;
server_name $name; server_name $name;
location / { location / {
proxy_set_header X-Real-IP $$remote_addr; proxy_set_header X-Real-IP $$remote_addr;
proxy_set_header X-Forwarded-For $$remote_addr; proxy_set_header X-Forwarded-For $$remote_addr;
proxy_set_header Host $$host; proxy_set_header Host $$host;
proxy_pass http://$ip:$port/; proxy_pass http://$ip:$port/;
} }
} }
""" """
location_template="""server { location_template="""# proxy for container '$containername'
server {
listen $listen; listen $listen;
server_name $name; server_name $name;
location / { location / {
@ -31,116 +36,124 @@ location_template="""server {
proxy_set_header X-Real-IP $$remote_addr; proxy_set_header X-Real-IP $$remote_addr;
proxy_set_header X-Forwarded-For $$remote_addr; proxy_set_header X-Forwarded-For $$remote_addr;
proxy_set_header Host $$host; proxy_set_header Host $$host;
proxy_pass http://$ip:$port/; proxy_pass http://$ip:$port/;
} }
} }
""" """
def get_pid(): def print_json(data):
with open(pid_file, 'r') as file: """Prints the given value in JSON to stdout. Use this for debugging only"""
return int(file.read()) print(json.dumps(data, sort_keys=True, indent=4))
def get_container_data(): def analyse_env_vars(inspect_data):
conn = http.client.HTTPConnection("localhost:2375") """Extracts the environment variables from the given result of an 'inspect
conn.request("GET", "/containers/json") container' call."""
response = conn.getresponse()
data = response.read().decode("UTF-8")
data = json.loads(data)
# print(json.dumps(data, sort_keys=True, indent=4))
conn.close()
return data
def inspect_container(container_id):
conn = http.client.HTTPConnection("localhost:2375")
conn.request("GET", "/containers/"+str(container_id)+"/json")
response = conn.getresponse()
data = response.read().decode("UTF-8")
data = json.loads(data)
# print(json.dumps(data, sort_keys=True, indent=4))
conn.close()
return data
def analyse_env_vars(data):
env_data = {} env_data = {}
for env_var in data: for env_var in inspect_data['Config']['Env']:
t = env_var.split("=") t = env_var.split("=")
env_data[t[0]] = t[1] env_data[t[0]] = t[1]
return env_data return env_data
def analyse_proxy_data(data): def analyse_proxy_data(data):
"""Extracts the data for the proxy configuration (envrionment variable
'PROXY_DATA' and converts it to a dictionary."""
proxy_data = {} proxy_data = {}
for proxy_var in data.split(','): for proxy_var in data['PROXY_DATA'].split(','):
t = proxy_var.split(":",1) t = proxy_var.split(":",1)
proxy_data[t[0]] = t[1] proxy_data[t[0]] = t[1]
return proxy_data return proxy_data
def handle_event(event): def extract_ip(inspect_data):
files = os.listdir(target_path) """extracts the container's ip from the given inspect data"""
print('deleting files') return inspect_data['NetworkSettings']['IPAddress']
for file in files:
if file.startswith('proxy_'):
os.remove(target_path+'/'+file)
event_data = json.loads(event)
containers_data = get_container_data()
for container_data in containers_data:
inspect_data = inspect_container(container_data['Id'])
env_data = analyse_env_vars(inspect_data['Config']['Env'])
if 'PROXY_DATA' in env_data:
container_id = container_data['Id']
ip = inspect_data['NetworkSettings']['IPAddress']
proxy_data = analyse_proxy_data(env_data['PROXY_DATA'])
server_name = '' def extract_name(inspect_data):
if 'server_name' in proxy_data: """extracts the container's name from the given inspect data"""
server_name = proxy_data['server_name'] return inspect_data['Name']
port = 0
if 'port' in proxy_data:
port = proxy_data['port']
location = '' def get_if_available(dict, key, defValue):
if 'location' in proxy_data: if key in dict:
location = proxy_data['location'] return dict[key]
else:
return defValue
listen ='*:80' def handle_container(id):
if 'ip' in proxy_data: """This function take a container's id and collects all data required
listen = proxy_data['ip']+':80' to create a proper proxy configuration. The configuration is then
written to the directory of temporary nginx files"""
inspect_data = client.inspect_container(id)
env_vars = analyse_env_vars(inspect_data)
if 'PROXY_DATA' in env_vars:
proxy_data = analyse_proxy_data(env_vars)
substitutes = {
'containername': extract_name(inspect_data),
'ip': extract_ip(inspect_data),
'location': get_if_available(proxy_data, 'location', ''),
'name': get_if_available(proxy_data, 'server_name', ''),
'port': get_if_available(proxy_data, 'port', 80),
'listen': get_if_available(proxy_data, 'ip', '*') + ':80'
}
logging.info('writing to %sproxy_%s', target_path, id)
with open(target_path + '/proxy_'+id, 'w') as file:
if substitutes['location'] == '':
del substitutes['location']
file.write(Template(non_location_template).substitute(substitutes))
else:
file.write(Template(location_template).substitute(substitutes))
print('writing /tmp/nginx/proxy_'+container_id) def reload_nginx_configuration():
with open('/tmp/nginx/proxy_'+container_id, 'w') as file: logging.info('HUPing nginx')
if location == '': os.kill(pid, signal.SIGHUP)
s = Template(non_location_template)
file.write(s.substitute(name=server_name,ip=ip,port=port,listen=listen))
else:
s = Template(location_template)
file.write(s.substitute(name=server_name,ip=ip,port=port,listen=listen,location=location))
print('HUPing nginx')
os.kill(pid, signal.SIGHUP)
if not os.path.exists(target_path): def get_pid():
os.mkdir(target_path) """This function reads the process id from the given file."""
with open(pid_file, 'r') as file:
return int(file.read())
pid = get_pid() def setup_logging():
logging.basicConfig(format='%(asctime)s [%(levelname)s]: %(message)s', level=logging.INFO)
conn = http.client.HTTPConnection("localhost:2375") if __name__ == '__main__':
try: setup_logging()
conn.request("GET", "/events")
except ConnectionRefusedError:
print('Docker does not expose events on its REST-API. Perhaps it is not running?')
sys.exit(-1)
response = conn.getresponse() # prepare required stuff
pid = get_pid()
logging.info('nginx pid: %s', str(pid))
if not os.path.exists(target_path):
logging.info('creating target path: %s', target_path)
os.mkdir(target_path)
client = Client(base_url='unix://var/run/docker.sock', version='1.15')
# handle all running containers existing at startup of this container
container_ids = client.containers(quiet=True)
for container_id in container_ids:
handle_container(container_id['Id'])
reload_nginx_configuration()
# hook to the events
for line in client.events():
line_str = line.decode("utf-8")
event = json.loads(line_str)
container_id = event['id']
try:
inspect_data = client.inspect_container(container_id)
ip = extract_ip(inspect_data)
except APIError:
ip = ''
# logging.info(event['status'] + " " + ip)
if ip == '':
logging.info('removing %sproxy_%s', target_path, container_id)
if os.path.exists(target_path + 'proxy_' + container_id):
os.remove(target_path + 'proxy_' + container_id)
else:
handle_container(container_id)
reload_nginx_configuration()
# event['timestamp'] = datetime.datetime.fromtimestamp(event['time']).strftime('%Y-%m-%d %H:%M:%S');
# print_json(event)
events = ""
while not response.closed:
data = response.read(80)
if len(data) != 0:
events += data.decode("UTF-8")
if events.find("{") != -1:
open_pos = events.index("{")
if events.find("}", open_pos) != -1:
close_pos = events.index("}", open_pos)+1
handle_event(events[open_pos:close_pos])
events = events[close_pos:]

4
start.sh Normal file
View File

@ -0,0 +1,4 @@
#!/bin/bash
nginx -c /etc/nginx.conf
/nginx_proxy.py