I have three docker containers,
java container (JC): for my java application (spring boot)
elasticsearch container (EC): for ElasticSearch
test container (TC): testing container to troubleshoot with ping test
Currently, the JC cannot see the EC by "name". And when I say "see" I mean if I do a ping on the JC to EC, I get a ping: unknown host. Interestingly, if I do a ping on the TC to EC, I do get a response.
Here is how I start the containers.
docker run -dit --name JC myapp-image
docker run -d --name EC elasticsearch:1.5.2 elasticsearch -Des.cluster.name=es
docker run --rm --name TC -it busybox:latest
Then, to ping EC from JC, I issue the following commands.
docker exec JC ping -c 2 EC
I get a ping: unknown host
With the TC, since I am already at the shell, I can just do a ping -c 2 EC and I get 2 replies.
I thought maybe this had something to do with my Java application, but I doubt it because I modified my Dockerfile to just stand up the container. The Dockerfile looks like the following.
FROM java:8
VOLUME /tmp
Note that you can create the above docker image by docker build -no-cache -t myapp-image ..
Also note that I have Docker Weave Net installed, and this does not seem to help getting the JC to see the EC by name. On the other hand, I tried to find the IP address of each container as follows.
docker inspect -f '{{ .NetworkSettings.IPAddress }}' JC --> 172.17.0.4
docker inspect -f '{{ .NetworkSettings.IPAddress }}' EC --> 172.17.0.2
docker inspect -f '{{ .NetworkSettings.IPAddress }}' TC --> 172.17.0.3
I can certainly ping EC from JC by IP address: docker exec JC ping -c 2 172.17.0.2. But getting the containers to see each other by IP address does not help as my Java application needs a hostname reference as a part of its configuration.
Any ideas on what's going on? Is it the container images themselves? Why would the busybox container image be able to ping the ElasticSearch container by name but the java container not?
Some more information.
VirtualBox 5.0.10
Docker 1.9.1
Weave 1.4.0
CentOS 7.1.1503
I am running docker inside a CentOS VM on a Windows 10 desktop as a staging environment before deployment to AWS
Any help is appreciated.
Within the same docker daemon, use the old --link option in order to update the /etc/hosts of each component and make sure one can ping the other:
docker run -d --name EC elasticsearch:1.5.2 elasticsearch -Des.cluster.name=es
docker run -dit --name JC --link ED myapp-image
docker run --rm --name TC -it busybox:latest
Then, a docker exec JC ping -c 2 EC should work.
If it does not, check if this isn't because of the base image and a security issue: see "Addressing Problems with Ping in Containers on Atomic Hosts".
JC is based on docker/_java:8, itself based on jessie-curl, jessie.
Containers in this default network are able to communicate with each other using IP addresses. Docker does not support automatic service discovery on the default bridge network. If you want to communicate with container names in this default bridge network, you must connect the containers via the legacy docker run --link option. docs.docker.org.
It should also work using the new networking.
docker network create -d bridge non-default
docker run --net non-default ...
There isn't a specific option which applies this behavior to the default network (AFAICT from looking at docker network inspect). I guess it's just triggered by the option "com.docker.network.bridge.default_bridge".
In the first part of another question, it's suggested this was changed in Docker 1.9. Note that Docker 1.9 was when they turned on the new networking system in the stable release. The section of the userguide that I quoted from above, did not exist in version 1.8. Docker 1.9.0 "bridge" versus a custom bridge network results in difference in hosts file and SSH_CLIENT env variable
Related
On my windows laptop I have created a Play application which runs fine if I execute its scripts directly. On the local machine, I access the application using localhost:9000 URL.
I have now created a Docker image of the application and have exposed port 9000
#this docker file copies prod specific files to container, eg logback_prod.xml and application_prod.conf
FROM openjdk:8
#ENV APP_NAME myapp
#ENV APP_VERSION 1.0-SNAPSHOT
...
#entrypoint is deploy/....
EXPOSE 9000
ENTRYPOINT ...
But I can't access the application on localhost:9000. I suspect that the image might be running on some other IP created by docker itself.
Am I correct? How can I access my application through the container? I don't need Kubernetes Services etc. as I already have that setup on another machine. My specific question is how to access the docker container directly.
UPDATE
I also tried running the docker image using --network="host" but that doesn't work either
UPDATE 2
Based on the suggestions below, I executed the following commands but still can't access the application.
docker run -p 9000:9000 --env-file env.txt imagename
I see the trace
[debug] a.i.TcpListener - Successfully bound to /0.0.0.0:9000
[info] p.c.s.AkkaHttpServer - Listening for HTTP on /0.0.0.0:9000
docker ps -a shows application is up with port binding 0.0.0.0:9000->9000/tcp
docker inspect shows IP - "IPAddress": "172.17.0.2"
but http://172.17.0.2:9000/ on Chrome doesn't work This site can’t be reached172.17.0.2
netstat -ab on cmd shows TCP 0.0.0.0:9000 LAPTOP-788I0GL1:0 LISTENING [com.docker.backend.exe]
Identify container's IP Address
Try these options with a running container.
<docker> refers to container's name or id
docker inspect --format '{{ .NetworkSettings.IPAddress }}' <docker>
//WINDOWS ONLY
docker inspect --format "{{ .NetworkSettings.IPAddress }}" <docker>
docker inspect <docker> | grep "IPAddress"
Grep not avaliable on Windows*
docker network inspect bridge
This last one would output all running containers' info that are allocated in the bridge network (default). Once identified, check the container's IPv4Address field.
Expose ports
In order to be able to connect to the a container's port, you could expose it. Note that the previous step is not needed in this case:
docker run -p 9000:9000 --env-file env.txt manuchadha25/mydockerimage
By default the docker will bind/listen to all interfaces on the host. The -p 9000:9000 option exposes the port, and as a result you get: 0.0.0.0:9000->9000/tcp
Now localhost:9000 succesfully connects to your docker process.
You can try the command docker inspect:
docker inspect <containerid>
for list the containers ids you can run the command:
docker ps
In order to get the ipAddress information you should look to node:
"IPAddress": "172.23.0.2"
In the json output produced.
Here is the documentation for docker inspect command.
I'm looking at documentation here, and see the following line:
$ docker run -it --network some-network --rm redis redis-cli -h some-redis
What should go in the --network some-network field? My docker run command in the field before did default port mapping of docker run -d -p 6379:6379, etc.
I'm starting my redis server with default docker network configuration, and see this is in use:
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
abcfa8a32de9 redis "docker-entrypoint.s…" 19 minutes ago Up 19 minutes 0.0.0.0:6379->6379/tcp some-redis
However, using the default bridge network produces:
$ docker run -it --network bridge --rm redis redis-cli -h some-redis
Could not connect to Redis at some-redis:6379: Name or service not known
Ignore the --network bridge command and use:
docker exec -it some-redis redis-cli
Docker includes support for networking containers through the use of network drivers. By default, Docker provides two network drivers for you, the bridge and the overlay drivers. You can also write a network driver plugin so that you can create your own drivers but that is an advanced task.
Read more here.
https://docs.docker.com/engine/tutorials/networkingcontainers/
https://docs.docker.com/v17.09/engine/userguide/networking/
You need to run
docker network create some-network
It doesn't matter what name some-network is, just so long as the Redis server, your special CLI container, and any clients talking to the server all use the same name. (If you're using Docker Compose this happens for you automatically and the network will be named something like directoryname_default; use docker network ls to find it.)
If your Redis server is already running, you can use docker network connect to attach the existing container to the new network. This is one of the few settings you're able to change after you've created a container.
If you're just trying to run a client to talk to this Redis, you don't need Docker for this at all. You can install the Redis client tools locally and run redis-cli, pointing at your host's IP address and the first port in the docker run -p option. The Redis wire protocol is simple enough that you can also use primitive tools like nc or telnet as well.
I was playing with ipvlan_mode=l3 by following the tutorial on docker github repo
https://gist.github.com/nerdalert/28168b016112b7c13040#ipvlan-l3-mode-example-usage
After running the commands my host and docker are not able to ping each other.
However two containers on diffrent subnets using the same parent iface are able to ping.
Commands :
docker network create -d ipvlan \
--subnet=192.168.214.0/24 \
--subnet=10.1.214.0/24 \
-o ipvlan_mode=l3 ipnet210
# Test 192.168.214.0/24 connectivity
$ docker run --net=ipnet210 --ip=192.168.214.10 -itd alpine /bin/sh
$ docker run --net=ipnet210 --ip=10.1.214.10 -itd alpine /bin/sh
# Test L3 connectivity from 10.1.214.0/24 to 192.168.212.0/24
$ docker run --net=ipnet210 --ip=192.168.214.9 -it --rm alpine ping -c 2 10.1.214.10
# Test L3 connectivity from 192.168.212.0/24 to 10.1.214.0/24
$ docker run --net=ipnet210 --ip=10.1.214.9 -it --rm alpine ping -c 2 192.168.214.10
Is there anything I'm missing ?
Thank in advance
You need to setup a static route on the host or upstream router to get a connection between host and docker subnet as mentioned in the documentation, end of the chapter:
In order to ping the containers from a remote Docker host or the container
be able to ping a remote host, the remote host or the physical network in
between need to have a route pointing to the host IP address of the
container’s Docker host eth interface.
For example (referenced to the picture) you have to create a route which point all traffic to subnet 172.16.20.0/24 to gateway 192.168.50.10/24.
I found this Q after reading about ipvlan l3 driver here
https://docs.docker.com/network/ipvlan/#ipvlan-l3-mode-example
And I see the same behavior on ubuntu 18.04 and ubuntu 20.04, both with:
kernel 5.4.0-96-generic
docker-ce 20.10.12
I assume it's by design like this that host can't even see those new networks with ip r
I would be very interested to hear how external connectivity for containers should work, in docs (link above) it's not explained, just simple picture without any details...not helpful at all.
Is there a way to have docker automatically give it’s containers a local IP address that you can reach with it’s ports exposed?
For example, LXC has ways to do this.
lxc-create -t ubuntu -n myname
lxc-start -n myname -d
Which will then assign a local IP which you can see via lxc-ls if you have a bridge configured:
lxc-ls -f
This is super convenient for throwing up a bunch of containers for testing out deployment/configuration management like ansible.
Is it possible to do something similar in docker without much headache? I come from using LXC and I’m not familiar with the networking modes.
LXC and Docker are very similar. When LXC is installed, a random subnet is picked for configuring the IP addresses of bridge and the containers attached to it. With Docker, the default subnet is 172.17.0.0/16, which can be customized if needed. Every container stared (unless using host network or network of another container) using docker run command are assigned an IP address from the above subnet.
docker ps lists all the containers running but unfortunately it doesn't show the IP addresses.
Looks like a small trick can show the IP addresses: (based on this post)
docker ps -q | xargs docker inspect --format '{{ .Id }} - {{ .Name }} - {{ .NetworkSettings.IPAddress }}'
Also you can expose the ports using the -p option of docker run command.
Example:
docker run -itd -p 8080:80 nginx
This starts the container on the docker bridge and also exposes the nginx on the host network via port 8080.
from_host_running_container# curl http://172.17.x.y
from_not_the_host_running_container # curl http://${HOST_IP}:8080
I have installed docker compose and used it a little. Then decided I did not need it it. Now when I create containers by hand they are assigned a network with an ip address, gateway and other things. When I inspected older containers before i installed docker compose they do not have these network settings.
I have tried unoinstalling docker compose and reinstalling docker which did not work. Is there anything I can do? The reason I am asking is I can't link containers together because every new container is assigned an ip address and other network settings.
Docker always does that, nothing to do with compose. Compose doesn't modify your Docker installation in any way, purely connects to the daemon to run commands under the hood.
By linking containers together I'm assuming you mean just so they can communicate with each other? --link is deprecated for some time now in favor of docker network .... Try the following:
$ docker network create test-net
$ docker run -d --name c1 --net test-net alpine:3.3 sleep 20000
$ docker run -it --name c2 --net test-net alpine:3.3 ping c1