Opened 5 years ago

Last modified 3 years ago

#658 new enhancement

Implement new type of "resolver" -- "system" [for Docker usage]

Reported by: tonn81@… Owned by:
Priority: minor Milestone:
Component: nginx-core Version: 1.7.x
Keywords: docker dns resolve system Cc:
uname -a: Linux 2b5fbf195b05 3.16.4-tinycore64 #1 SMP Thu Oct 23 16:14:24 UTC 2014 x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.7.7 built by gcc 4.7.2 (Debian 4.7.2-5) TLS SNI support enabled configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-mail --with-mail_ssl_module --with-file-aio --with-http_spdy_module --with-cc-opt='-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,--as-needed' --with-ipv6

Description

It would be great if I could use "system" resolver for converting DNS name into IP. That would make usage of nginx inside Docker way easier.

When you use dynamic resolving (see example below) you have to set up your DNS server IP by "resolver" parameter.

It is fine for the most of the cases but in some setups (e.g with Docker) you don't have a dedicated DNS server but have resolving configured on your machine (using /etc/hosts, /etc/resolv and so one). Yes, my DNS names are not public, so I cannot use 8.8.8.8 or whatever public DNS.

That brings us to idea to use the same nginx code that does static resolving on nginx.conf parsing -- the one that is using system function to resolve it.

Since you already have dynamic name resolving (so you solved all surrounding issues like non-blocking resolving, etc.) it seems to be a minor change to use another function for resolving.

My current config (not valid!):

server {
    listen 80;
    server_name ~(?P<project>[^.]+)\.localhost$;
    location / {
        proxy_pass http://$project:8000;
    }
}

All projects have entry in /etc/hosts generated by Docker on run.

Ideal solution:

server {
    listen 80;
    server_name ~(?P<project>[^.]+)\.localhost$;
    resolver system; # here is the trick
    location / {
        proxy_pass http://$project:8000;
    }
}

Change History (5)

comment:1 Changed 5 years ago by vbart

Since you already have dynamic name resolving (so you solved all surrounding issues like non-blocking resolving, etc.) it seems to be a minor change to use another function for resolving.

It solved by implementing our own asynchronous resolver. Since the system's resolver is blocking, it can't be used for dynamic name resolution.

comment:2 Changed 5 years ago by vbart

Actually, the right and optimal way to solve your problem would be generating nginx configuration and thus avoiding dynamic resolving.

comment:3 Changed 5 years ago by thresh

And there's also a Docker image that does exactly that: https://github.com/jwilder/nginx-proxy.

comment:4 Changed 5 years ago by tonn81@…

I didn't say it is impossible now -- you could still generate nginx config on fly or install lightweight DNS server (e.g. dnsmasq) locally.

Still I find this topic pretty demanded feature -- while googling I found it was one of common misunderstanding / feature lacking -- that you cannot use system resolving dynamically.

Don't get me wrong -- this solution may be not finely efficient (though I don't see much difference with current dynamic resolving -- especially while we cache it) -- but it allows you to solve some tasks in more simple and straightforward way. And sure, for high-load you would need some another solution.

Replying to Valentin V. Bartenev:

It solved by implementing our own asynchronous resolver. Since the system's resolver is blocking,
it can't be used for dynamic name resolution.

Is it possible to wrap system's resolver into async function?

Or maybe at least include an option to read /etc/hosts before trying out given DNS server? That would be best in matter of time_spend/results ratio.

Last edited 5 years ago by tonn81@… (previous) (diff)

comment:5 Changed 3 years ago by erin.dru@…

Heres a workaround for people using Docker.

export NAMESERVER=`cat /etc/resolv.conf | grep "nameserver" | awk '{print $2}' | tr '\n' ' '`

What this does is take all the nameserver entries from /etc/resolv.conf and print them in a line, so you can use them with nginx's resolver directive.

Your Dockerfile will need to have a custom script for the entrypoint that generates the config file and then starts nginx.

Lets say you have a file called nginx.conf.template that looks something like:

...snip...
http {
  server {

    resolver $NAMESERVER valid=10s;

    ...snip....  
    }
  }
}

Your startup script can then use the envsubst program to generate an nginx.conf and then start nginx. eg:

#!/bin/bash
if [ "$NAMESERVER" == "" ]; then
	export NAMESERVER=`cat /etc/resolv.conf | grep "nameserver" | awk '{print $2}' | tr '\n' ' '`
fi

echo "Nameserver is: $NAMESERVER"

echo "Copying nginx config"
envsubst '$NAMESERVER' < /nginx.conf.template > /nginx.conf

echo "Using nginx config:"
cat /nginx.conf

echo "Starting nginx"
nginx -c /nginx.conf -g "daemon off;"
Note: See TracTickets for help on using tickets.