Our web server changes will be a bit trickier due to a quirk/feature of the NGINX configuration processing that may also impact you if you do Java-based DNS resolution. Essentially, NGINX caches DNS entries so hard that effectively, once it reads the configuration files, any new DNS resolution within that configuration will not actually take place at all unless some extra flags ( resolver ) are specified. With the Docker service being constantly mutable and relocatable, this is a serious issue that must be worked around to function properly on the Swarm. Here, you have a couple of options:
- Run a DNS forwarder (such as dnsmasq) in parallel with NGINX and use that as the resolver. This requires running both dnsmasq and NGINX in the same container.
- Populate the NGINX configuration container start with the same resolvers from the system using something such as envsubst: this requires all containers to be in the same user-defined network.
- Hardcode the DNS resolver IP (127.0.0.11): this also requires all containers to be in the same user-defined network.
For robustness, we will use the second option, so copy the web server from the previous chapter into a new folder and rename it to nginx_main_site.conf.template. We will then add a resolver configuration to it and a variable $APP_NAME for our proxy host endpoint:
server {
listen 8080;
server_name _;
resolver $DNS_RESOLVERS;
root /srv/www/html;
location ~/. {
deny all;
}
location / {
auth_basic "Authentication required";
auth_basic_user_file /srv/www/html/.htpasswd;
proxy_pass http://$APP_NAME:8000;
}
}
Since NGINX does not handle environment variable substitution in the configuration files, we will write a wrapper script around it. Add a new file called start_nginx.sh and include the following content in it that takes the host's resolvers and generates the new main_site config:
#!/bin/bash -e
export DNS_RESOLVERS=$(cat /etc/resolv.conf | grep 'nameserver' | awk '{ print $2 }' | xargs echo)
cat /etc/nginx/conf.d/nginx_main_site.conf.template | envsubst '$DNS_RESOLVERS $APP_NAME' > /etc/nginx/conf.d/nginx_main_site.conf
nginx -g 'daemon off;'
To get this to run, we finally need to make sure we start NGINX with this script instead of the one built in, so we need to modify our Dockerfile as well.
Open up our Dockerfile and make sure that it has the following:
FROM nginx:latest
RUN apt-get update -q &&
apt-get dist-upgrade -y &&
apt-get install openssl &&
apt-get clean &&
apt-get autoclean
EXPOSE 8080
ENV SRV_PATH /srv/www/html
ARG PASSWORD=test
RUN rm /etc/nginx/conf.d/default.conf
COPY start_nginx.sh /usr/local/bin/
RUN mkdir -p $SRV_PATH &&
chown nginx:nginx $SRV_PATH &&
printf "user:$(openssl passwd -crypt $PASSWORD) " >> $SRV_PATH/.htpasswd &&
chmod +x /usr/local/bin/start_nginx.sh
COPY nginx_main_site.conf.template /etc/nginx/conf.d/
CMD ["/usr/local/bin/start_nginx.sh"]
Here, the main change is the start up script CMD override and turning the configuration into a template with the rest pretty much left alone.