fixed problem with listening on different IPs which is not possible in the classical way in docker
This commit is contained in:
parent
b37c8ab7de
commit
a0c246169c
34
README.md
34
README.md
|
@ -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).
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue