Reputation: 155
I'm trying to build a docker image for local PHP development based on openSUSE, PHP7 and Apache 2.4. Apache should resolve...
http://localhost -> /srv/www/htdocs (openSUSE standard)
http://myapp -> /srv/www/myapp/public
...
(http://myapp.localhost, http://myapp.dev etc. would also be ok, if that's easier to achieve.)
In order to configure the vhosts, I added /etc/apache2/vhosts.d/myapp.conf with this content:
<VirtualHost *:80>
ServerName localhost
DocumentRoot /srv/www/htdocs
</VirtualHost>
<VirtualHost *:80>
ServerName myapp
DocumentRoot "/srv/www/myapp/public"
<Directory "/srv/www/myapp/public">
AllowOverride None
</Directory>
</VirtualHost>
This file seems to be used by Apache. apachectl -S leads to this output:
VirtualHost configuration:
*:80 is a NameVirtualHost
default server localhost (/etc/apache2/vhosts.d/myapp.conf:2)
port 80 namevhost localhost (/etc/apache2/vhosts.d/myapp.conf:2)
port 80 namevhost myapp (/etc/apache2/vhosts.d/myapp.conf:10)
ServerRoot: "/srv/www"
Main DocumentRoot: "/srv/www/htdocs"
Main ErrorLog: "/var/log/apache2/error_log"
Mutex ssl-stapling-refresh: using_defaults
Mutex rewrite-map: using_defaults
Mutex ssl-stapling: using_defaults
Mutex ssl-cache: using_defaults
Mutex default: dir="/run/" mechanism=default
Mutex mpm-accept: using_defaults
PidFile: "/var/run/httpd.pid"
Define: SYSCONFIG
Define: DUMP_VHOSTS
Define: DUMP_RUN_CFG
User: name="wwwrun" id=30
Group: name="www" id=8
Now, localhost is resolved correctly and myapp is not. Chrome says "ERR_NAME_NOT_RESOLVED".
I guess, this is because there is no entry in /etc/hosts for myapp. However, as far as I understand, docker does not allow /etc/hosts to be modified. I tried to do this with sed in my Dockerfile:
RUN sed -i 's/^127.0.0.1.*$/127.0.0.1 localhost myapp/g' /etc/hosts
in order to add the mapping myapp -> 127.0.0.1 to /etc/hosts. However, docker build says
sed: cannot rename /etc/sedLXNJtt: Device or resource busy
My question is thus: How do I tell my container to resolve myapp correctly?
Upvotes: 2
Views: 4293
Reputation: 7261
This is unsurprising, you're asking the DNS resolver of your web browser, an arbitrary program on your local host likely using the system resolver and which has no knowledge of Docker containers, to somehow figure out which Docker container IP to resolve that name to.
A nice approach I've seen in the past is to attach a container running an SSH daemon to the Docker bridge network of your target services. You can then use SSH's dynamic application-level port forwarding feature and configure your browser to use a SOCKS proxy set up by the SSH client on a port of your choice and which tunnels inside the Docker network. If you configure your browser to also resolve DNS queries via the proxy you should be able to reach the Docker embedded DNS server, which will by default answer appropriately to queries for domain names that correspond to the container names.
What's nice about this is that:
You don't need SSH for this approach of course, just something that talks SOCKS and that can interface with an arbitrary virtual network interface. It's just that the SSH client and server combo makes it very easy to set up and experiment with today without writing any code. Disclaimer: I've never tried the approach personally but I see no reason it wouldn't work.
You can add an entry in your local hosts file for every container as you already found. This is obviously more straightforward, but tooling to automate that approach might be more involved. In effect, you would need to write a DNS resolver or server that integrates with Docker, perhaps with UI to disambiguate between names claimed by different containers in different Docker networks. Again some tools might already exist but I have personally not heard of any.
Alternatively you can imagine a non-ambiguous scheme like $container_name.$network_name.localhost
, though you're now requiring some containers (like HTTP servers that do virtual hosting as in your setup) to know about system-level concerns (which network they're in) where you'd rather want it to be transparent (different developers on your team might use different network names, maybe they're even testing multiple branches of the same codebase at once on different networks). You might use things like environment substitution in docker-compose to have this still run without any configuration (assuming you can always pass these settings down to the container processes through environment variables/configuration file templating), but this might be trickier in practice.
If you do this you can have your default system resolver target that DNS server (and fallback to your normal servers), which can either be a good or a bad thing depending on what you want to do. Note that in my experience I don't know of many programs that allow you to pick an arbitrary name resolver or even arbitrary DNS servers (as most rely on the system resolver). So, if you want application-level configuration this is probably not the best approach (SOCKS support is more common).
Upvotes: 1