Multi-container docker on AWS - Nginx use host machine /etc/hosts resolver
I have a multi-container docker environment on Amazon Elastic Beanstalk with the following Dockerrun.aws.json
file:
{
"AWSEBDockerrunVersion": 2,
"containerDefinitions": [
{
"name": "web",
"memoryReservation": 256,
"image": "my/nginx/repo/image",
"portMappings": [
{
"hostPort": 80,
"containerPort": 80
}
],
"links": [
"api"
],
"essential": true
},
{
"name": "api",
"memoryReservation": 256,
"image": "my-api/repo",
"essential": true,
"portMappings": [
{
"hostPort": 3000,
"containerPort": 80
}
]
}
]
}
Ultimately I want the node app served by nginx to resolve requests to named addresses from linked containers, so in my web
image (node app) I'd like to make a request to http://api/some/resource
and let nginx resolve that to the api container.
Now, since docker adds a host entry for the api container due to the specified link, I want the nginx server to resolve addresses from the hosts etc/hosts
file, however as I found out, nginx uses it's own resolver. After researching the issue a bit I found out that in non-Elastic Beanstalk multi-container solutions and with user-defined networks, the resolver would be provided by docker on 127.0.0.11
, however since it is currently not possible to define user-defined networks in the Dockerrun.aws.json
, I keep looking for a different solution. The links
can be resolved inside the container, ping
ing api does work, however, nginx does it's own thing there.
I have read about dnsmasq
as well, however, I wanted to get this running without installing this package, do I even have a choice here ?
There is no way to force nginx to use the entries from /etc/hosts.
You can however use a map { } in your nginx config to tell nginx how to convert hostnames to IPs.
You would need a script to convert your /etc/hosts to a format that can be used in a map, i.e. hostname ip
vs ip hostname
.
Here is an example map:
map $container_hostname $container_ip {
default 127.0.0.1;
containerA X.X.X.X;
containerB Y.Y.Y.Y;
}
Later in the config file you can do:
server_name ~^(www\.)?(?<container_hostname>.+)$;
location / {
proxy_pass http://$container_ip:80;
}
nginx will match the requested server_name
and store it in $container_hostname:
http://nginx.org/en/docs/http/server_names.html#regex_names
Then it will look up the hostname in the map, obtain the corresponding IP and pass it to proxy_pass.
More info on map: http://nginx.org/en/docs/http/ngx_http_map_module.html