docker images fail to start because of unknownhost exception while trying to communicate with external host - docker

I have a spring boot service which runs fine as spring boot app. I have created docker image out of it using docker file. When the image start, application seems starting fine till a point when it try to resolve external host (I have couple fo external service configured based on profile and I am running in dev profile which will communicate with external service like consule , mysql etc). It throws unknownhost exception. Same application run fine and able to run and communicate with external services while running it as spring boot app/service in my local machine . It seems like the issue is between host and docker container not able to use dns of host. Any help, how can I resolve the issue ?

From the Docker documentation:
https://docs.docker.com/config/containers/container-networking/#ip-address-and-hostname
DNS services
By default, a container inherits the DNS settings of the Docker
daemon, including the /etc/hosts and /etc/resolv.conf.You can override
these settings on a per-container basis.
Flag Description
--dns The IP address of a DNS server. To specify multiple DNS servers, use
multiple --dns flags. If the container cannot reach any of the IP
addresses you specify, Google’s public DNS server 8.8.8.8 is added,
so that your container can resolve internet domains.
--dns-search A DNS search domain to search non-fully-qualified hostnames.
To specify multiple DNS search prefixes, use multiple --dns-search flags.
--dns-opt A key-value pair representing a DNS option and its value. See your
operating system’s documentation for resolv.conf for valid options.
--hostname The hostname a container uses for itself. Defaults to the container’s
ID if not specified.
See also:
Docker docs: Configure container DNS
java.net.UnknownHostException on Docker

Related

How do I make host.docker.internal work with custom dns configuration enabled?

I have docker compose running with several containers. One of those containers is a dns server running bind. In my docker daemon configuration I specify the dns like this:
"dns" : [
"10.1.1.8", /* static ip address of my dockerized bind container defined in compose */
"x.x.x.x", /* my companies internal vpn dns */
"8.8.8.8" /* google dns */
]
This all works fine. My containers in the compose file will use the bind server running on 10.1.1.8 for dns lookup and then fall back on my companies internal dns and lastly googles dns for external websites.
Docker provides a special dns host.docker.internal which should point at the host IP (lets say you want docker containers to connect to services running locally but not on docker). I want to use this in a few containers which should allow the container to reference the host IP address without hardcoding an IP which can change. In fact docker inserts this value into the hosts file (windows/system32/driver/etc/host) on the host operating system and updates it when you host IP gets assigned a new dns.
The issue is docker uses dns to resolve "host.docker.internal". When using my custom dns configuration in the daemon it breaks things and I get issues reaching the host os service. I spent 2 hours debugging this issue till I realized host.docker.internal starts working only when I delete the dns configuration from the daemon config. Is there any way to make docker resolve the dns correctly and still use custom dns bind server on the same machine? Can I somehow update the daemon dns to also point at some docker dns ip address?
Have you considered to rely on Docker Compose and how it helps defining custom DNS addressing policies.
I provide you the link to the Compose DNS configuration official guide.

DNS issue when using Docker

From a Spring Boot application running on a docker container, I am trying to connect to Rabbit MQ, Storm and other services which are also running on a docker container. It is working fine when using IP address like x.x.x.x but the same is not working when using the DNS name for that IP. In the command prompt I am able to ping and get a successful response for the same DNS name. Requesting for your help and support in this issue.
You said that you can resolve DNS on the command line. If you mean the command line of the host machine (outside of of the docker container), then the issue is probably with the container's own DNS settings.
A container has it's own network settings. Take a look at the /etc/resolv.conf file being used by the Spring Boot container - this will show you that container's DNS settings.

Remote Docker container by hostname

How do you access remote Docker container by its hostname?
I need to access remote Docker containers by its hostnames (or some constant IP's) for development and testing purposes. I have tried:
looking for any DNS approach (have not found any clues),
importing /ets/hosts (probably impossible),
creating tunnes (only this works but it is very time consuming).
It's the same as running any other process on a host, Docker or not Docker: you access it via the host name or IP address of the host and the port the service is listening on (the first port of the docker run -p argument). Docker containers don't have externally visible individual IP addresses any more than non-Docker HTTP or ssh daemons do.
If you do have DNS infrastructure available to you, you could set up CNAME records to resolve particular service names to the specific hosts that are running them.
One solution that may help you is some sort of service registry; in the past I've used Consul with some success. You can configure Consul with some health checks or other probes ("look for an HTTP service on port 12345 that answers GET / calls"), and it will provide its own DNS service ("okay, http://whatevername.service.consul:12345/ will reach your service on whichever hosts it happens to be running on").
Nothing in the Docker infrastructure specifically helps this. Using /etc/hosts is distinctly not a best practice: the name-to-IP mapping needs to be kept in sync across all machines and you'll start wishing you had a network service to publish it for you, which is exactly what DNS is for.

how to define HTTP health check in a consul container for a service on the same host?

We are using a consul agent on a host that also runs a service. (RabbitMQ)
To verify that the service is ready we have defined a curl based health check.
however, we are using the registrator to inject this check using env variable.
SERVICE_CHECK_SCRIPT=curl hostname:15672/....
problem is, we've also told the consul-agent that its hostname is the same as the host.
(We must have this feature since we want to see the correct hostname registered with the consul cluster.
When the consul agent runs the health check, it looks for the URL on its own container...
this obviously fails...
does anybody knows how to define this health check (we are using mesos to do it) so that curl will attempt to connect to the right ip?
You can use Registrator's HTTP health check (provided that you run Consul inside progrium/docker-consul container), for example:
ENV SERVICE_CHECK_HTTP=/howareyou
ENV SERVICE_CHECK_INTERVAL=5s
This check will run check-http script provided by docker-consul, which resolves target container's IP and port using the Docker API.
The other option is to configure Consul DNS to listen on Docker's bridge IP (which is already done in progrium/docker-consul's run script), and launch Docker daemon with the global DNS option pointing to the same IP, e.g. docker -d --bip 10.0.42.1/24 --dns 10.0.42.1 --dns 8.8.8.8.
After that Consul DNS will be available in any of your containers, including the docker-consul one, which means that you can run curl http://my-app.service.consul:12345/howareyou, or even query SRV records, e.g. with dig -t SRV, to obtain both IP and port of a service. And then you may add 10.0.42.1 to the host's resolv.conf to gain the ability to query Consul DNS not only within containers, but from the host OS too.
The preferred method, imho, is to use Registrator's SERVICE_CHECK_HTTP, but setting up Consul DNS for your containers is worth doing anyway.
Both these methods require running Consul agent in client mode on each of your application hosts, but Consul agent, when ran in this mode, uses such a tiny amount of system resources that you'll hardly notice it. And you need it anyway to perform health checks :)

Cross container communication with Docker

An application server is running as one Docker container and database running in another container. IP address of the database server is obtained as:
sudo docker inspect -f '{{ .NetworkSettings.IPAddress }}' db
Setting up JDBC resource in the application server to point to the database gives "java.net.ConnectException".
Linking containers is not an option since that only works on the same host.
How do I ensure that IP address of the database container is visible to the application server container?
If you want private networking between docker containers on remote hosts you can use weave to setup an overlay network between docker containers. If you don't need a private network just expose the ports using the -p switch and configure the addresses of the host machine as the destination IP in the required docker container.
One simple way to solve this would be using Weave. It allows you to create many application-specific networks that can span multiple hosts as well as datacenters. It also has a very neat DNS-based service discovery mechanism.
I should disclaim, I am one of Weave engineering team.
Linking containers is not an option since that only works on the same host.
So are you saying your application is a container running on docker server 1 and your db is a container on docker server 2? If so, you treat it like ordinary remote hosts. Your DB port needs to be exposed on docker server 2 and that IP:port needs to be configured into your application server, typically via environment variables.
The per host docker subnetwork is a Private Network. It's perhaps possible to have this address be routable, but it would be much pain. And it's further complicated because container IP's are not static.
What you need to do is publish the ports/services up to the host (via PORT in dockerfile and -p in your docker run) Then you just do host->host. You can resolve hosts by IP, Environment Variables, or good old DNS.
Few things were missing that were not allowing the cross-container communication:
WildFly was not bound to 0.0.0.0 and thus was only accepting requests on eht0. This was fixed using "-b 0.0.0.0".
Firewall was not allowing the containers to communication. This was removed using "systemctl stop firewall; systemctl disable firewall"
Virtual Box image required a Host-only adapter
After this, the containers are able to communicate. Complete details are available at:
http://blog.arungupta.me/2014/12/wildfly-javaee7-mysql-link-two-docker-container-techtip65/

Resources