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
import os
import sys
import http.client
import json
import signal
from docker import Client
from docker.errors import APIError
from string import Template
import json
import datetime
import signal
import os
import logging
import sys
target_path="/tmp/nginx"
pid_file="/run/nginx.pid"
non_location_template = """server {
target_path="/tmp/nginx/"
pid_file="/var/run/nginx.pid"
non_location_template = """# proxy for container '$containername'
server {
listen $listen;
server_name $name;
location / {
proxy_set_header X-Real-IP $$remote_addr;
proxy_set_header X-Forwarded-For $$remote_addr;
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;
server_name $name;
location / {
@ -31,116 +36,124 @@ location_template="""server {
proxy_set_header X-Real-IP $$remote_addr;
proxy_set_header X-Forwarded-For $$remote_addr;
proxy_set_header Host $$host;
proxy_pass http://$ip:$port/;
proxy_pass http://$ip:$port/;
}
}
"""
def get_pid():
with open(pid_file, 'r') as file:
return int(file.read())
def print_json(data):
"""Prints the given value in JSON to stdout. Use this for debugging only"""
print(json.dumps(data, sort_keys=True, indent=4))
def get_container_data():
conn = http.client.HTTPConnection("localhost:2375")
conn.request("GET", "/containers/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 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):
def analyse_env_vars(inspect_data):
"""Extracts the environment variables from the given result of an 'inspect
container' call."""
env_data = {}
for env_var in data:
for env_var in inspect_data['Config']['Env']:
t = env_var.split("=")
env_data[t[0]] = t[1]
return env_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 = {}
for proxy_var in data.split(','):
for proxy_var in data['PROXY_DATA'].split(','):
t = proxy_var.split(":",1)
proxy_data[t[0]] = t[1]
return proxy_data
def handle_event(event):
files = os.listdir(target_path)
print('deleting files')
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'])
def extract_ip(inspect_data):
"""extracts the container's ip from the given inspect data"""
return inspect_data['NetworkSettings']['IPAddress']
server_name = ''
if 'server_name' in proxy_data:
server_name = proxy_data['server_name']
port = 0
if 'port' in proxy_data:
port = proxy_data['port']
def extract_name(inspect_data):
"""extracts the container's name from the given inspect data"""
return inspect_data['Name']
location = ''
if 'location' in proxy_data:
location = proxy_data['location']
def get_if_available(dict, key, defValue):
if key in dict:
return dict[key]
else:
return defValue
listen ='*:80'
if 'ip' in proxy_data:
listen = proxy_data['ip']+':80'
def handle_container(id):
"""This function take a container's id and collects all data required
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)
with open('/tmp/nginx/proxy_'+container_id, 'w') as file:
if location == '':
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)
def reload_nginx_configuration():
logging.info('HUPing nginx')
os.kill(pid, signal.SIGHUP)
if not os.path.exists(target_path):
os.mkdir(target_path)
def get_pid():
"""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")
try:
conn.request("GET", "/events")
except ConnectionRefusedError:
print('Docker does not expose events on its REST-API. Perhaps it is not running?')
sys.exit(-1)
if __name__ == '__main__':
setup_logging()
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