No route to host within docker container - docker

I am running a Debian docker container on a Windows 10 machine which needs to access a particular url on port 9000 (164.16.240.30:9000)
The host machine can access it fine via the browser, however when I log in to the terminal and run wget 172.17.240.30:9000 I get failed: No route to host.
In an attempt to resolve this I added:
ports:
- 9000:9000
to the docker-compose.yml file, however that doesn't seem to have made any difference.
In case you can't guess I'm new to this so what would you try next?
Entire docker-compose.yml file:
version: '3.4'
services:
tokengeneratorapi:
network_mode: host
image: ${DOCKER_REGISTRY}tokengeneratorapi
build:
context: .
dockerfile: TokenGeneratorApi/Dockerfile
ports:
- 5000:80
- 9000
environment:
ASPNETCORE_ENVIRONMENT: local
SSM_PATH: /ic/env1/tokengeneratorapi/
AWS_ACCESS_KEY_ID:
AWS_SECRET_ACCESS_KEY:
Command I'm running:
docker-compose build --build-arg BRANCH=featuretest --build-arg CHANGE_ID=99 --build-arg CHANGE_TARGET=develop --build-arg SONAR_SERVER=164.16.240.30

It seems it's the container having connectivity issues so your proposed solution is likely to not work, as that is only mapping a host port to a container port (considering your target URL is not the actual host).
Check out https://docs.docker.com/compose/compose-file/#network_mode and try setting it to host.

Your browser has access to 164.16.240.30:9000, because it is going through proxy (typical enteprise environment), so the proxy has network connectivity to 164.16.240.30. It doesn't mean that also your host has the same network connectivity. Actually, it looks like your host doesn't have that one. That is the reason why direct wget from the container or from terminal has error No route to host.
Everything must go through the proxy. Try to configure proxy properly - linux apps use environment variables http_proxy,https_proxy usually, but apps may have own option to configure proxy, eventualy you may configure it on the source code level. It depends on used app/code.

I think the issue is that you use host mode in your docker compose config file and do you have IPTABLES firewall allowed for the ports in the debian machine? How about windows?
network_mode: host
which actually bypasses the docker bridge completely so the ports section you specify is not applied. All the ports will be opened on the host system. You can check with
nestat -tunlp | grep 5000
And you will see that the port 5000 is not open and mapped to the 80 of the docker as you would expect. However ports 80 and 9000 should be open on the debian network but not binded to any docker bridge only to the debian ip.
From here: https://docs.docker.com/network/host/
WARNING: Published ports are discarded when using host network mode
As a solution could be to remove the network_mode line and it will work as expected.

Your code doesn't allow your container access to 164.16.240.30:9000. You should wget 164.16.240.30:9000 from the terminal instead of 172.17.240.30:9000.

Related

Connect to docker container on Windows

I've read this post and I've tried adding ports: "7080:7080" in docker-compose.yml but still can't connect to the container using 172.18.0.2:7080 (btw I'm a docker newbie)
The container is one of several in a DockStation project on Windows 10. The image I'm using is for OpenLiteSpeed with WordPress.
The docker-compose.yml file contents is below:
version: '2'
services:
gnome-3-28-1804:
image: ubuntudesktop/gnome-3-28-1804
firefox:
image: jlesage/firefox
browser-box:
image: jim3ma/browser-box
openlitespeed:
image: litespeedtech/openlitespeed
ports:
- "7080:7080"
Any ideas please?
UPDATE: IP 172.17.0.1 appears to be the default bridge gateway IP so I assume 172.18.0.2 for this container is in some way related to that; Docker and DockStation are both running locally on host 10.0.0.10 Not sure if the setup should even be using a bridge. http://localhost:7080/ says ERR_CONNECTION_REFUSED
UPDATE 2: I'm using Docker for Windows (Docker Desktop). Tried turning off the Windows firewall but makes no difference. Still getting ERR_CONNECTION_REFUSED for http://localhost:7080/ and http://10.0.0.10:7080/. There are 3 other containers in the project but not running, only the LiteSpeed one is running.
UPDATE 3: I created a new project and installed tutum/hello-world/ then ran the new container. The hello-world container is running and I've not found any error in the logs, but neither localhost nor 10.0.0.10 will connect, the error in Chrome is ERR_CONNECTION_REFUSED. Same if I run docker run -d -p 80 tutum/hello-world in Windows command prompt.
What is this IP (172.18.0.2) representing? Is it a remote machine where DockStation is running?
If this is a case, check if this port is publicly available on that machine. You did add ports section to the Dockerfile which will map container's port to machine's port - but it is a matter whether e.g. firewall blocks outside access to that port.
I would first troubleshoot it by trying to access localhost:7080 from 172.18.0.2 machine - if it works, your Docker configuration is good and you need to look for the problem in that machine's configuration (e.g. firewall).
I tried your Compose file on my system and it works as expected - I can access port 7080 both using my host's system IP and hostname and the container's IP and ports 80 and 443 using only the container's IP (since they're not mapped to any of the host's ports).
You did not specify whether you're using Docker for Windows or Docker Toolbox - DockStation works with both, but if you're using Docker Toolbox, then you'll have to use the virtual machine's IP or hostname to access port 7080, instead of localhost. If you're using Docker for Windows, then I do not understand what is going on - are you sure the containers are running?
As for where those IP's you mentioned come from - 172.17.0.1 is most likely your hosts IP on Docker's default bridged network. Docker-compose, by default, creates its own bridged networks for every project. In your case, in your project's network, your host's IP would be 172.18.0.1. You can view Docker's networks with command docker network ls and their details with docker network inspect <network-name>.
You should not use any of those IP's for any reason, since there's no guarantee they'll remain the same. If you need to connect from outside, map internal container ports to your Docker's host's ports, like you did with port 7080 and if you need containers to connect to each other - with docker-compose you can use service names as hostnames, without it you have to connect them to the same, non-default, bridged Docker network and use their container names as hostnames.
This solution worked for me.
docker run -d -p 127.0.0.1:80:80 tutum/hello-world
Apparently you have to specify you want the port exposed under localhost. Then localhost entered in the browser address bar loaded the Hello World page - hurrah!
Once I changed the ports in docker-compose.yml to '127.0.0.1:80:80' then it also worked when run from DockStation.

Run API tests in docker using http://localhost:port

There is an app for book flights and our team is implementing integrations to interact with the flight booking app. So now there is a need to test their APIs in CI environment.
Therefore, I have created a Dockerfile in my API testing framework:
FROM golang:1.13
ADD . /app
WORKDIR /app
RUN go mod download
CMD ["make", "test", "$URL=", "$INTEGRATION=", "$TESTTYPE=", "$TAGS="]
And also I have created a docker-compose.yml file in the integration repo which I should test:
version: '3'
services:
tests:
image: int-tests:latest
environment:
- URL=http://localhost:3000/
- INTEGRATION=pitane
- TESTTYPE=integration
- TAGS=quotes
I have tried to build and run the integration tests using localhost. Locally I can do it without using docker. But inside docker I can't use localhost link of the integration to call their endpoints. Is there any way to do it?
This is the error message that I'm getting:
msg="Post http://localhost:3000/v1/quote: dial tcp 127.0.0.1:3000: connect: connection refusedUnable to get response"
msg="Post http://localhost:3000/v1/quote: dial tcp 127.0.0.1:3000:
connect: connection refusedUnable to get response"
You are trying to connect to the container itself. Use host ip address or network_mode: "host"
UPD
You can find out your host ip with ip route | awk '/default/ { print $3 }' and then use this ip in the URL environment variable.
Or you can get rid of network isolation of the container at all setting network_mode: "host" in docker-compose.yml (not preferred way though)
https://docs.docker.com/compose/compose-file/#network_mode
In this case localhost will denote host machine localhost.
Also you can use host.docker.internal if you use Mac (not preferred way)
https://docs.docker.com/docker-for-mac/networking/
At docker file expose appropriate port (port, others will connect to your service)
EXPOSE 80
If you want to access that started container at hosting machine you have to map that port to your hosting machine. You do it with docker command:
docker run -p 80:80 ....
or with docker compose:
ports:
- '80:80'

Access localhost of Docker container

I am running docker on mac and am trying to set up a development environment for an angular project in a docker container.
My docker-compose setup currently looks like this:
version: '3.7'
services:
dev:
build:
context: .
dockerfile: "${DOCKERFILE_DIR}"
working_dir: "${CONTAINER_DIR}"
ports:
- "3000:4200"
- "3001:8080"
volumes:
- "nfsmount:${CONTAINER_DIR}"
tty: true
volumes:
nfsmount:
driver: local
driver_opts:
type: nfs
o: addr=host.docker.internal,rw,nolock,hard,nointr,nfsvers=3
device: ":/System/Volumes/Data/${SOURCE_DIR}"
The thing is, when I run ng serve inside the docker container, it serves to the localhost:4200 of the docker container and not to the exposed ports of the container. This means that the port mapping of "3000:4200" is insufficient for me to connect localhost:3000 from my host machine to localhost:4200 of my docker container.
Sure, an easy solution would just be to serve to 0.0.0.0:4200 of my docker container by using ng serve --host 0.0.0.0 instead. However, I am trying to mimic my development environment as much as possible, so I was wondering if there was any other way to connect localhost:4200 to 0.0.0.0:4200 inside my docker container (or better still, connect localhost:3000 of my host machine directly to localhost:4200 of my docker container).
Any help is greatly appreciated!
It is not possible unless you use host networking inside the container. When you create a container, the container gets it's own network namespace. The loopback interface is accessible only to the processing running in the same network namespace i.e., the processes inside the container only and hence cannot be accessed from the host.
Instead of running your container in separate network namespace, you can run it in the host network using network_mode: "host" parameter in the docker compose. This should work for your use case if you insist on not binding to 0.0.0.0 inside the container. - https://docs.docker.com/compose/compose-file/#network_mode

Understanding Docker network isolation

I have created the following docker-compose file...
version: '3'
services:
db-service:
image: postgres:11
volumes:
- ./db:/var/lib/postgresql/data
expose:
- 5432
environment:
- POSTGRES_PASSWORD=mypgpassword
networks:
- net1
pgadmin:
image: dpage/pgadmin4
volumes:
- ./pgadmin:/var/lib/pgadmin
ports:
- 5000:80
environment:
- PGADMIN_DEFAULT_EMAIL=me#gmail.com
- PGADMIN_DEFAULT_PASSWORD=mypass
networks:
- net1
networks:
net1:
external: false
From reading various docs on the docker site, my expectation was that the pgadmin container would be able to access the postgres container via port 5432 but that I should not be able to access postgres directly from the host. However, I am able to use psql to access the database from the host machine.
In fact, if I comment out the expose and ports lines I can still access both containers from the host.
What am I missing about this?
EDIT - I am accessing the container by first running docker container inspect... to get the IP address. For the postgres container I'm using
psql -h xxx.xxx.xxx.xxx -U postgres
It prompts me for the password and then allows me to do all the normal things you would expect.
In the case of the pgadmin container I point my browser to the IP address and get the pgadmin interface.
Note that both of those are being executed from a terminal on the host, not from within either container. I've also commented out the expose command and can still access the postgres db.
docker-compose creates a network for those two containers to be able talk to each-other when you run it, through a DNS service which will contain pointers to each service, by name.
So from the perspective of the pgadmin container, the dbserver can be reached under hostname db-service (because that is what you named your service in the docker-compose.yml file).
So, that traffic does not go through the host, as you were assuming, but through the aforementioned network.
For proof, docker exec -it [name-of-pg-admin-container] /bin/sh and type:
ping db-service. You will see that docker provides a DNS resolution and that you can even open a connection to the normal postgres port there.
The containers connect one with another by bridge network net1.
When you expose port, you create port forwarding in your IPTABLES for connecting host network and net1.
Stop expose 5432 port in your db-service and you see that you can't connect from your host to db-service.
Docker assigns an internal IP address to each container. If you happen to have this address, and it happens to be reachable, then Docker doesn’t do anything specific to firewall it off. On a Linux host in particular, if specific Docker network is on 172.17.0.0/24, the host might have a 172.17.0.1 address and a specific container might be 172.17.0.2, and they can talk to each other this way.
Using the Docker-internal IP addresses is not a best practice. If you ever delete and recreate a container, its IP address will change; on some host platforms you can’t directly access the private IP addresses even from the same host; the private IP addresses are never reachable from other hosts. In routine use you should never need to docker inspect a container.
The important level of isolation you do get here is that the container isn’t accessible from other hosts unless you explicitly publish a port (docker run -p option, Docker Compose ports: option). The setup here is much more uniform than for standard applications: set up the application inside the container to listen on 0.0.0.0 (“all host interfaces”, usually the default), and then publish a port or not as your needs require. If the host has multiple interfaces you can publish a port on only one of them (even if the application doesn’t natively support that).

accessing a docker container from another container

I created two docker containers based on two different images. One of db and another for webserver. Both containers are running on my mac osx.
I can access db container from host machine and same way can access webserver from host machine.
However, how do I access db connection from webserver?
The way I started db container is
docker run --name oracle-db -p 1521:1521 -p 5501:5500 oracle/database:12.1.0.2-ee
I started wls container as
docker run --name oracle-wls -p 7001:7001 wls-image:latest
I can access db on host by connecting to
sqlplus scott/welcome1#//localhost:1521/ORCLCDB
I can access wls on host as
http://localhost:7001/console
It's easy.
If you have two or more running container, complete next steps:
docker network create myNetwork
docker network connect myNetwork web1
docker network connect myNetwork web2
Now you connect from web1 to web2 container or the other way round.
Use the internal network IP addresses which you can find by running:
docker network inspect myNetwork
Note that only internal IP addresses and ports are accessible to the containers connected by the network bridge.
So for example assuming that web1 container was started with: docker run -p 80:8888 web1 (meaning that its server is running on port 8888 internally), and inspecting myNetwork shows that web1's IP is 172.0.0.2, you can connect from web2 to web1 using curl 172.0.0.2:8888).
Easiest way is to use --link, however the newer versions of docker are moving away from that and in fact that switch will be removed soon.
The link below offers a nice how too, on connecting two containers. You can skip the attach portion, since that is just a useful how to on adding items to images.
https://web.archive.org/web/20160310072132/https://deis.com/blog/2016/connecting-docker-containers-1/
The part you are interested in is the communication between two containers. The easiest way, is to refer to the DB container by name from the webserver container.
Example:
you named the db container db1 and the webserver container web0. The containers should both be on the bridge network, which means the web container should be able to connect to the DB container by referring to its name.
So if you have a web config file for your app, then for DB host you will use the name db1.
if you are using an older version of docker, then you should use --link.
Example:
Step 1: docker run --name db1 oracle/database:12.1.0.2-ee
then when you start the web app. use:
Step 2: docker run --name web0 --link db1 webapp/webapp:3.0
and the web app will be linked to the DB. However, as I said the --link switch will be removed soon.
I'd use docker compose instead, which will build a network for you. However; you will need to download docker compose for your system. https://docs.docker.com/compose/install/#prerequisites
an example setup is like this:
file name is base.yml
version: "2"
services:
webserver:
image: moodlehq/moodle-php-apache:7.1
depends_on:
- db
volumes:
- "/var/www/html:/var/www/html"
- "/home/some_user/web/apache2_faildumps.conf:/etc/apache2/conf-enabled/apache2_faildumps.conf"
environment:
MOODLE_DOCKER_DBTYPE: pgsql
MOODLE_DOCKER_DBNAME: moodle
MOODLE_DOCKER_DBUSER: moodle
MOODLE_DOCKER_DBPASS: "m#0dl3ing"
HTTP_PROXY: "${HTTP_PROXY}"
HTTPS_PROXY: "${HTTPS_PROXY}"
NO_PROXY: "${NO_PROXY}"
db:
image: postgres:9
environment:
POSTGRES_USER: moodle
POSTGRES_PASSWORD: "m#0dl3ing"
POSTGRES_DB: moodle
HTTP_PROXY: "${HTTP_PROXY}"
HTTPS_PROXY: "${HTTPS_PROXY}"
NO_PROXY: "${NO_PROXY}"
this will name the network a generic name, I can't remember off the top of my head what that name is, unless you use the --name switch.
IE docker-compose --name setup1 up base.yml
NOTE: if you use the --name switch, you will need to use it when ever calling docker compose, so docker-compose --name setup1 down this is so you can have more then one instance of webserver and db, and in this case, so docker compose knows what instance you want to run commands against; and also so you can have more then one running at once. Great for CI/CD, if you are running test in parallel on the same server.
Docker compose also has the same commands as docker so docker-compose --name setup1 exec webserver do_some_command
best part is, if you want to change db's or something like that for unit test you can include an additional .yml file to the up command and it will overwrite any items with similar names, I think of it as a key=>value replacement.
Example:
db.yml
version: "2"
services:
webserver:
environment:
MOODLE_DOCKER_DBTYPE: oci
MOODLE_DOCKER_DBNAME: XE
db:
image: moodlehq/moodle-db-oracle
Then call docker-compose --name setup1 up base.yml db.yml
This will overwrite the db. with a different setup. When needing to connect to these services from each container, you use the name set under service, in this case, webserver and db.
I think this might actually be a more useful setup in your case. Since you can set all the variables you need in the yml files and just run the command for docker compose when you need them started. So a more start it and forget it setup.
NOTE: I did not use the --port command, since exposing the ports is not needed for container->container communication. It is needed only if you want the host to connect to the container, or application from outside of the host. If you expose the port, then the port is open to all communication that the host allows. So exposing web on port 80 is the same as starting a webserver on the physical host and will allow outside connections, if the host allows it. Also, if you are wanting to run more then one web app at once, for whatever reason, then exposing port 80 will prevent you from running additional webapps if you try exposing on that port as well. So, for CI/CD it is best to not expose ports at all, and if using docker compose with the --name switch, all containers will be on their own network so they wont collide. So you will pretty much have a container of containers.
UPDATE: After using features further and seeing how others have done it for CICD programs like Jenkins. Network is also a viable solution.
Example:
docker network create test_network
The above command will create a "test_network" which you can attach other containers too. Which is made easy with the --network switch operator.
Example:
docker run \
--detach \
--name db1 \
--network test_network \
-e MYSQL_ROOT_PASSWORD="${DBPASS}" \
-e MYSQL_DATABASE="${DBNAME}" \
-e MYSQL_USER="${DBUSER}" \
-e MYSQL_PASSWORD="${DBPASS}" \
--tmpfs /var/lib/mysql:rw \
mysql:5
Of course, if you have proxy network settings you should still pass those into the containers using the "-e" or "--env-file" switch statements. So the container can communicate with the internet. Docker says the proxy settings should be absorbed by the container in the newer versions of docker; however, I still pass them in as an act of habit. This is the replacement for the "--link" switch which is going away. Once the containers are attached to the network you created you can still refer to those containers from other containers using the 'name' of the container. Per the example above that would be db1. You just have to make sure all containers are connected to the same network, and you are good to go.
For a detailed example of using network in a cicd pipeline, you can refer to this link:
https://git.in.moodle.com/integration/nightlyscripts/blob/master/runner/master/run.sh
Which is the script that is ran in Jenkins for a huge integration tests for Moodle, but the idea/example can be used anywhere. I hope this helps others.
You will have to access db through the ip of host machine, or if you want to access it via localhost:1521, then run webserver like -
docker run --net=host --name oracle-wls wls-image:latest
See here
Using docker-compose, services are exposed to each other by name by default. Docs.
You could also specify an alias like;
version: '2.1'
services:
mongo:
image: mongo:3.2.11
redis:
image: redis:3.2.10
api:
image: some-image
depends_on:
- mongo
- solr
links:
- "mongo:mongo.openconceptlab.org"
- "solr:solr.openconceptlab.org"
- "some-service:some-alias"
And then access the service using the specified alias as a host name, e.g mongo.openconceptlab.org for mongo in this case.
Environment: Windows 10, Docker Desktop version 4.5.1.
Use hostname host.docker.internal to access services running on your host machine from inside a container.
See: https://docs.docker.com/desktop/windows/networking/#use-cases-and-workarounds
I run PostgreSQL in one container and my app in a separate container.
I configure the app database connection to use host.docker.internal as the hostname and it just works.
Consider Example
We Create two containers here PostgreSQL server and pgadmin(for accessing servers like PHPMyAdmin, SQL studio, workbench).
Exposed port
PostgreSql --->5436
Pgadmin --->5050
After adding a server in pgadmin hostname as localhost.It will show a connection error. Because Docker container pgadmin getting localhost as their system instead we need PostgreSQL IP to solve the problem.
docker network create con
docker network connect con app1
docker network connect con app2
This command gets connected container IP address and other details.
docker network inspect con
Now you can see the IP address shown in the network inspect. Choose the Postgres container IP. You can access other exposed ports through this IP. Here postgre 5432 is only exposed.Now set hostname as the container ip and it will work.
You can use the default docker network. If you don't want to go through any docker networking, you can do this:
Copy the ip address in Docker subnet in Resources>Network in Docker Preferences in Mac:
Docker preferences screenshot
As you can see from the screenshot link the ip address is
192.168.65.0
You just need to replace “localhost” in your containers config file with “192.168.65.1" (i.e. IP address picked + 1 ).
You can start your containers and should be set for local development/testing.
For some more details, you can see my article:
Connect Docker containers the easy way
In my case, the host connection in the application to a container from an other container by the IP provide by the bridge didn't work.
But it works with the name of the container (see my screenshot).
So you can replace the IP by the name of the container.

Resources