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,15 +1,19 @@
#!/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 / {
@ -21,7 +25,8 @@ non_location_template = """server {
} }
""" """
location_template="""server { location_template="""# proxy for container '$containername'
server {
listen $listen; listen $listen;
server_name $name; server_name $name;
location / { location / {
@ -36,111 +41,119 @@ location_template="""server {
} }
""" """
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 def get_if_available(dict, key, defValue):
if 'port' in proxy_data: if key in dict:
port = proxy_data['port'] return dict[key]
location = ''
if 'location' in proxy_data:
location = proxy_data['location']
listen ='*:80'
if 'ip' in proxy_data:
listen = proxy_data['ip']+':80'
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: else:
s = Template(location_template) return defValue
file.write(s.substitute(name=server_name,ip=ip,port=port,listen=listen,location=location))
print('HUPing nginx') 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))
def reload_nginx_configuration():
logging.info('HUPing nginx')
os.kill(pid, signal.SIGHUP) os.kill(pid, signal.SIGHUP)
if not os.path.exists(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())
def setup_logging():
logging.basicConfig(format='%(asctime)s [%(levelname)s]: %(message)s', level=logging.INFO)
if __name__ == '__main__':
setup_logging()
# 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) os.mkdir(target_path)
pid = get_pid() client = Client(base_url='unix://var/run/docker.sock', version='1.15')
conn = http.client.HTTPConnection("localhost:2375") # handle all running containers existing at startup of this container
try: container_ids = client.containers(quiet=True)
conn.request("GET", "/events") for container_id in container_ids:
except ConnectionRefusedError: handle_container(container_id['Id'])
print('Docker does not expose events on its REST-API. Perhaps it is not running?') reload_nginx_configuration()
sys.exit(-1)
response = conn.getresponse() # hook to the events
for line in client.events():
line_str = line.decode("utf-8")
event = json.loads(line_str)
events = "" container_id = event['id']
while not response.closed: try:
data = response.read(80) inspect_data = client.inspect_container(container_id)
if len(data) != 0: ip = extract_ip(inspect_data)
events += data.decode("UTF-8") except APIError:
if events.find("{") != -1: ip = ''
open_pos = events.index("{")
if events.find("}", open_pos) != -1: # logging.info(event['status'] + " " + ip)
close_pos = events.index("}", open_pos)+1 if ip == '':
handle_event(events[open_pos:close_pos]) logging.info('removing %sproxy_%s', target_path, container_id)
events = events[close_pos:] 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)

4
start.sh Normal file
View File

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