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
|
||||
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
|
||||
Containers that should be proxied neet meta information in the environment variable *PROXY_DATA* available.
|
||||
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
|
||||
* **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
|
||||
|
||||
## 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)
|
||||
if 'PROXY_DATA' in 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 = {
|
||||
'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'
|
||||
'listen': '*:80'
|
||||
}
|
||||
logging.info('writing to %sproxy_%s', target_path, id)
|
||||
with open(target_path + '/proxy_'+id, 'w') as file:
|
||||
|
@ -108,6 +113,26 @@ def get_pid():
|
|||
with open(pid_file, 'r') as file:
|
||||
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():
|
||||
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')
|
||||
|
||||
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
|
||||
container_ids = client.containers(quiet=True)
|
||||
for container_id in container_ids:
|
||||
|
|
Loading…
Reference in New Issue