Can't resolve set hostname from another docker container in same network - docker

I've had db and server container, both running in the same network. Can ping db host by its container id with no problem.
When I set a hostname for db container manually (-h myname), it had an effect ($ hostname returns set host), but I can't ping that hostname from another container in the same network. Container id still pingable.
Although it works with no problem in docker compose.
What am I missing?

Hostname is not used by docker's built in DNS service. It's a counterintuitive exception, but since hostnames can change outside of docker's control, it makes some sense. Docker's DNS will resolve:
the container id
container name
any network aliases you define for the container on that network
The easiest of these options is the last one which is automatically configured when running containers with a compose file. The service name itself is a network alias. This lets you scale and perform rolling updates without reconfiguring other containers.
You need to be on a user created network, not something like the default bridge which has DNS disabled. This is done by default when running containers with a compose file.
Avoid using links since they are deprecated. And I'd only recommend adding host entries for external static hosts that are not in any DNS, for container to container, or access to other hosts outside of docker, DNS is preferred.

I've found out, that problem can be solved without network using --add-host option. Container's IP can be gain using inspect command.
But when containers in the same network, they are able to access each other via it names.

As stated in the docker docs, if you start containers on the default bridge network, adding -h myname will add this information to
/etc/hosts
/etc/resolv.conf
and the bash prompt
of the container just started.
However, this will not have any effect to other independent containers. (You could use --link to add this information to /etc/hosts of other containers. However, --link is deprecated.)
On the other hand, when you create a user-defined bridge network, docker provides an embedded DNS server to make name lookups between containers on that network possible, see Embedded DNS server in user-defined networks. Name resolution takes the container names defined with --name. (You
will not find another container by using its --hostname value.)
The reason, why it works with docker-compose is, that docker-compose creates a custom network for you and automatically names the containers.
The situation seems to be a bit different, when you don't specify a name for the container yourself. The run reference says
If you do not assign a container name with the --name option, then the daemon generates a random string name for you. [...] If you specify a name, you can use it when referencing the container within a Docker network.
In agreement with your findings, this should be read as: If you don't specify a custom --name, you cannot use the auto-generated name to look up other containers on the same network.

Related

How docker process communication between different containers on default bridge on the same host?

Here is my situation:
First,I run a MySQL container(IP:172.17.0.2) on centOS;
Then I run a Nacos contanier with specified datasource(MySQL above) on the same host, but i didn't use the ip of the MySQL container, instead I used the ip of the bridge Gateway(172.17.0.1)(two containers both link to the default bridge).
What surprised me was that Nacos works well, it can query config data from MySQL container normally.
How did this happen? I have read some documention but didn't get the answer.It really confused me.
On modern Docker installations, try to avoid using the default bridge network. docker network create a network (it doesn't need any special options, but it does need to be created) and then launch your containers on --net that network. If you're using Compose, it creates a ("user bridge") network named default for you.
On your CentOS host, if you run ifconfig, you should see a docker0 interface with the 172.17.0.1 address. When you launch a container with the docker run -p option, that container is accessible via the first port number on all host interfaces, including the docker0 interface.
Meanwhile, inside a container (on the default bridge network), it sees that same IP address as the normal IPv4 gateway address (try docker run --rm busybox route -n). So, when you connect to 172.17.0.1:3306, you're connecting out to the host, and then connecting to the published port of the database container.
This isn't a totally standard way to connect between containers, though it will work. You should prefer using Docker named networks, which will let you connect to another container using the container's name without manually doing any IP-address lookups. If you really can't move off of the default bridge network, then the standard approach is to --link to the other container, but this entire path is considered outdated.

Make the DNS server of docker container another docker container running DNSmasq

I have a set of docker containers created with docker compose, which creates a "user-defined" bridge network.
One of these docker containers is running DNSmasq so we can define custom (internal) domain names to point to local IPs.
Trouble is, none of the other docker containers can resolve these domain names. I think the issue is that I can't get the docker DNS to forward its requests to the docker container running DNSmasq (i.e. it doesn't even know it exists).
As a test, I did a docker network inspect <network created by docker compose> and noted the IP address of the DNSmasq container. Then, in one of the other containers' /etc/resolv.conf, I set nameserver to that IP address. Then I can resolve all these internal domains names.
Sadly, putting dnsmasq in there doesn't work, despite the fact that the user-defined network has automatic service discovery enabled.
It seems that one way to make this work then is to force my DNSmasq container to always have the same IP, and then make sure the other docker containers point to that as their nameserver, e.g. by defining the network explicitly in the compose file.
Is there no other way? I'd rather not have to define the entire network to replicate this automatically created one when all I want is to know the IP address of one container.

Is there a way to add a hostname to an EXISTING docker container?

I have some containers that communicate via their IP from the network docker.
I can use the option -h or --hostname when running a new container but I want to set the hostname for existing container.
Is it possible?
One way is to create network and add different container in this network.
When adding container in the network, you can use the --alias option of docker network. Like this:
Create a network:
docker network create <my-network-name>
Add containers in the network:
docker network connect --alias <hostname-container-1> <my-network-name> <container-1>
docker network connect --alias <hostname-container-2> <my-network-name> <container-2>
docker network connect --alias <hostname-container-3> <my-network-name> <container-3>
Enjoy.
So each container can see other container by the alias (the alias is used as hostname).
Generally, you would need to stop/restart a container, in order to run it again with -h (--hostname) (unless you used --net=host)
If you cannot stop the container, you can try and (in an attached bash session) edit its /etc/hostname.
The hostname is immutable once the container is created (although technically you can modify /etc/hostname).
As suggested in another answer, you cannot change the hostname by stopping or restarting the container. There are not Docker engine client parameters for the start command that affect hostname. That wouldn't make sense anyway as starting a container simply launches the ENTRYPOINT process in a container filesystem that has already been created (i.e. /etc/hostname has already been written).
It is possible to synchronize the container hostname with the host by using the --uts=host parameter when the container is created. This shares the UTS namespace. I would not recommend --net=host unless you also want to share the host network devices (i.e. bypass the Docker bridge).

Docker doesn't resolve hostname

I need to know the hostnames (or ip addresses) of some container running on the same machine.
As I already commented here (but with no answer yet), I use docker-compose. The documentation says, compose will automatically create a hostname entry for all container defined in the same docker-compose.yml file:
Each container for a service joins the default network and is both reachable by other containers on that network, and discoverable by them at a hostname identical to the container name.
But I can't see any host entry via docker exec -it my_container tail -20 /etc/hosts.
I also tried to add links to my container, but nothing changed.
Docker 1.10 introduced some new networking features which include an internal DNS server where host lookups are done.
On the default bridge network (docker0), lookups continue to function via /etc/hosts as they use to. /etc/resolv.conf will point to your hosts resolvers.
On a user defined network, Docker will use the internal DNS server. /etc/resolv.conf will have an internal IP address for the Docker DNS server. This setup allows bridge, custom and overlay networks to work in a similar fashion. So an overlay network on swarm will populate host data from across the swarm like a local bridge network would.
The "legacy" setup was maintained so the new networking features could be introduced without impacting existing setups.
Discovery
The DNS resolver is able to provide IP's for a docker compose service via the name of that service.
For example, with a web and db service defined, and the db service scaled to 3, all db instances will resolve:
$ docker-compose run --rm web nslookup db
Name: db
Address 1: 172.22.0.4 composenetworks_db_2.composenetworks_mynet
Address 2: 172.22.0.5 composenetworks_db_3.composenetworks_mynet
Address 3: 172.22.0.3 composenetworks_db_1.composenetworks_mynet

questions about docker --link parameter

As we know, in one host with docker daemon, containers connect to the docker0 bridge, and so containers can access each other by default.
Then what's the use of --link option? Is it any different with the direct access by ip way?
What does it actually do?
From the Docker docs:
When you set up a link, you create a conduit between a source container and a recipient container. The recipient can then access select data about the source
When two containers are linked, Docker will set some environment variables in the target container to enable programmatic discovery of information related to the source container.
And some more:
In addition to the environment variables, Docker adds a host entry for the source container to the /etc/hosts file. Here's an entry for the web container:
So, basically --link creates a set of environment variables and adds some entries to the /etc/hosts file in order to ease communication. But, the containers are still directly accessed via IP.
When you create a container using --link option, Docker exposes the linked container into the new one in two ways:
It creates a entry in /etc/hosts with the IP of the linked container and the alias given when creating the link.
It exposes some information as environmental variables about the linked container. As Docker documentation shows:
Docker will then also define a set of environment variables for each port that is exposed by the source container. The pattern followed is:
<name>_PORT_<port>_<protocol> will contain a URL reference to the port. Where <name> is the alias name specified in the --link parameter (e.g. webdb), <port> is the port number being exposed, and <protocol> is either TCP or UDP. The format of the URL will be: <protocol>://<container_ip_address>:<port> (e.g. tcp://172.17.0.82:8080). This URL will then be split into the following 3 environment variables for convenience:
<name>_PORT_<port>_<protocol>_ADDR will contain just the IP address from the URL (e.g. WEBDB_PORT_8080_TCP_ADDR=172.17.0.82).
<name>_PORT_<port>_<protocol>_PORT will contain just the port number from the URL (e.g. WEBDB_PORT_8080_TCP_PORT=8080).
<name>_PORT_<port>_<protocol>_PROTO will contain just the protocol from the URL (e.g. WEBDB_PORT_8080_TCP_PROTO=tcp).
It is not differences if you access via IP, but using links let setting the container ignoring the ip that will be assigned by Docker Daemon. Check Docker documentation for further information.
If you start the docker using --icc=false option, the container can't communicate to each other by default. You must use --link to connect two containers.

Resources