fixed problem with listening on different IPs which is not possible in the classical way in docker

This commit is contained in:
Joachim Lusiardi 2015-02-19 19:27:52 +01:00
parent b37c8ab7de
commit a0c246169c
2 changed files with 59 additions and 8 deletions

View File

@ -1,13 +1,6 @@
# Automated Nginx reverse Proxy for Docker Webservices # Automated Nginx reverse Proxy for Docker Webservices
This image attaches to the docker event queue and creates/removes proxy settings in the contained nginx. This image attaches to the docker event queue and creates/removes proxy settings in the contained nginx.
## Starting the container
The container is started as:
`docker run --name auto_proxy -d -v /var/run/docker.sock:/var/run/docker.sock -p 80:80 docker_nginx_auto_proxy`
The socket must be handed in so the container can get the events.
## How it works ## How it works
Containers that should be proxied neet meta information in the environment variable *PROXY_DATA* available. Containers that should be proxied neet meta information in the environment variable *PROXY_DATA* available.
This variable must be of the following format: This variable must be of the following format:
@ -20,3 +13,30 @@ The following options are possible:
* **port**(optional, defaults to 80) the port on the target container * **port**(optional, defaults to 80) the port on the target container
* **ip**(optional, defaults to listen on all IPs) the IP on which the proxy should listen. * **ip**(optional, defaults to listen on all IPs) the IP on which the proxy should listen.
* **location**(optional) if the proxied web application is not running on the /-path * **location**(optional) if the proxied web application is not running on the /-path
## Starting the container
Since the container uses Docker's internal event reporting, it needs access to the daemon. At the
moment, only access via UNIX socket ist possible. Because of that, the socket has to be handed
into the container (*-v /var/run/docker.sock:/var/run/docker.sock*).
### Single IP / All IPs
This option is used if your Docker Host has only one IP or if there is no need to differentiate between different IPs regarding wether a Web App is available on it.
Run the container like this:
`docker run --name auto_proxy -d -v /var/run/docker.sock:/var/run/docker.sock -p 80:80 docker_nginx_auto_proxy`
That means that the container exposes all Wep Apps on all IPs. Do **not** use the *ip* option from above on the target containers. The *PROXY_DATA* environment variables would be something like:
`PROXY_DATA=server_name:cooldomain.test.com,port:8080,location=/webApp`
### Multiple IPs
This option is used if your Docker Host has multiple IPs (perhaps a public IP in the internet and a private IP on a VPN). It is possible to expose some Web Apps only to the private network.
One container must be started for each IP that should host Web Apps. For example, if there is a public IP of 1.2.3.4 and a private IP 10.1.2.3, then 2 Containers would be started:
`docker run --name auto_proxy_public -d -v /var/run/docker.sock:/var/run/docker.sock -p 1.2.3.4:80:80 docker_nginx_auto_proxy`
`docker run --name auto_proxy_private -d -v /var/run/docker.sock:/var/run/docker.sock -p 10.1.2.3:80:80 docker_nginx_auto_proxy
`
If a target container does **not** have the *ip* option set, it listens on **all** IP adresses and will be handled by both containers. If a container uses, e.g.
`PROXY_DATA=server_name:cooldomain.test.com,port:8080,location=/webApp,ip=10.1.2.3`
Then it will be only available on the private 10.1.2.3 IP (perhaps using a VPN).

View File

@ -83,13 +83,18 @@ def handle_container(id):
env_vars = analyse_env_vars(inspect_data) env_vars = analyse_env_vars(inspect_data)
if 'PROXY_DATA' in env_vars: if 'PROXY_DATA' in env_vars:
proxy_data = analyse_proxy_data(env_vars) proxy_data = analyse_proxy_data(env_vars)
container_listen_ip = get_if_available(proxy_data, 'ip', '0.0.0.0')
if container_listen_ip != '0.0.0.0' and container_listen_ip not in listen_ips:
logging.info('container "%s"(%s) does not listen on %s.', extract_name(inspect_data), container_listen_ip, str(listen_ips))
return
logging.info('container "%s"(%s) is allowed to listen on %s.', extract_name(inspect_data), container_listen_ip, str(listen_ips))
substitutes = { substitutes = {
'containername': extract_name(inspect_data), 'containername': extract_name(inspect_data),
'ip': extract_ip(inspect_data), 'ip': extract_ip(inspect_data),
'location': get_if_available(proxy_data, 'location', ''), 'location': get_if_available(proxy_data, 'location', ''),
'name': get_if_available(proxy_data, 'server_name', ''), 'name': get_if_available(proxy_data, 'server_name', ''),
'port': get_if_available(proxy_data, 'port', 80), 'port': get_if_available(proxy_data, 'port', 80),
'listen': get_if_available(proxy_data, 'ip', '*') + ':80' 'listen': '*:80'
} }
logging.info('writing to %sproxy_%s', target_path, id) logging.info('writing to %sproxy_%s', target_path, id)
with open(target_path + '/proxy_'+id, 'w') as file: with open(target_path + '/proxy_'+id, 'w') as file:
@ -108,6 +113,26 @@ def get_pid():
with open(pid_file, 'r') as file: with open(pid_file, 'r') as file:
return int(file.read()) return int(file.read())
def get_docker_id():
"""This function extracts the container's id from /proc/self/cgroup."""
id = ''
with open('/proc/self/cgroup', 'r') as file:
lines = file.read().split('\n')
for line in lines:
index = line.find('docker-')
if index != -1:
id = line[index+7:-6]
break
return id
def get_listen_ips():
inspect_data = client.inspect_container(get_docker_id())
logging.info('count %s', len(inspect_data['NetworkSettings']['Ports']['80/tcp']))
ips = []
for data in inspect_data['NetworkSettings']['Ports']['80/tcp']:
ips.append(data['HostIp'])
return ips
def setup_logging(): def setup_logging():
logging.basicConfig(format='%(asctime)s [%(levelname)s]: %(message)s', level=logging.INFO) logging.basicConfig(format='%(asctime)s [%(levelname)s]: %(message)s', level=logging.INFO)
@ -123,6 +148,12 @@ if __name__ == '__main__':
client = Client(base_url='unix://var/run/docker.sock', version='1.15') client = Client(base_url='unix://var/run/docker.sock', version='1.15')
listen_ips = get_listen_ips()
logging.info('Listening on %s.', listen_ips)
if len(listen_ips) != 1:
logging.error('auto_proxy should only listen on 1 IP at a time, everything else can have security implications.')
exit()
# handle all running containers existing at startup of this container # handle all running containers existing at startup of this container
container_ids = client.containers(quiet=True) container_ids = client.containers(quiet=True)
for container_id in container_ids: for container_id in container_ids: