Access localhost of Docker container - docker

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

Related

Connect to docker-compose container from docker image

I've got a Docker image which accepts a DATABASE_URL env and start the container with
docker run -p 3000:3000 -e DATABASE_URL=mysql://root:foobar#localhost:3309/app app_image
On startup the container should run migrations on a database bootstraped from a docker-compose.yml file:
version: '3'
services:
database:
image: mysql:8.0
environment:
- MYSQL_DATABASE=app
- MYSQL_ROOT_PASSWORD=foobar
ports:
- "3309:3306"
volumes:
- db:/var/lib/mysql
volumes:
db:
Unfortunately, I always get Can't reach database at localhost:3309. I assume it has something to do with the network settings - but how to configure these settings in order to make it work?
I've tried many different configurations (e.g. database, 127.0.0.1, etc. instead of localhost) but couldn't make it work and I'm honestly running out of ideas.
Thanks!
Some clarifications:
Unless you specifically bind containers to the same host e.g. --network host or link them together in docker compose using links Links documentation, container A will not be able to reach anything on container B via localhost.
Docker compose, unless specified differently in the docker-compose.yaml file, automatically creates a separate network for all of the containers that are managed by that compose file, its name is usually based on the folder the file is in.
You can view it using docker network ls
that means, any container not managed by that compose file, is not part of the same network by default.
One option easy enough option that you have (among many probably):
Decide on a network name which the compose file and you container will agree on
create this network beforehand (before starting the standalone container and the compose file), the network will probably be in bridge mode
docker network docs docker network create -d bridge my-bridge-network
add it to the compose file so that docker compose uses it instead of the auto-created one
networks:
- my-bridge-network
when starting the stand-alone container, specify which network to attach it to
docker run -p 3000:3000 -e DATABASE_URL=mysql://root:foobar#database:3309/app --network my-bridge-network app_image
notice that the IP/HOSTNAME for the database container is according to the service name in the compose file, you can change that using hostname: some-other-hostname in the yaml.
all containers should now be on the same network, each one has a different IP/Hostname using this method (so cant use localhost for inter-container communication)
Alternative option:
use network: host for both the compose file and the stand-alone container, they can talk to each other using localhost.
i dont recommend this option, and cant find a good enough reason to use it over other options.

No route to host within docker container

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.

Docker alternative to --network host on macOS and Windows

I have two docker containers:
database
app that consumes the database
I run my database container like this:
docker run --name my-db -p 127.0.0.1:3306:3306 my-db-image
And my app container like this:
docker run --name my-app --network host -it my-app-image
This works fine on Linux. I can access the DB from both the host system and the app container. Perfect.
However --network host does not work on Mac and Windows:
The host networking driver only works on Linux hosts, and is not supported on Docker for Mac, Docker for Windows, or Docker EE for Windows Server.
(source: https://docs.docker.com/network/host/)
I can still access the database via 127.0.0.1:3306 from the main host, but I cannot access it from the app container.
How can I solve this issue? How can I let the app container connect to the database (and keep accessing also to the DB from the main host using 127.0.0.1:3306)?
I've tried using host.docker.internal and gateway.docker.internal but it doesn't work.
I've also tried to launch both containers using --network my-network after creating my-network with docker network create my-network but it doesn't work.
I can't figure out how to solve this issue.
For multiple services, it can often be easier to create a docker-compose.yml file that will launch all the services and any networks needed to connect them.
version: '3'
services:
my-db:
image: my-db-image
ports:
- "3306:3306"
networks:
- mynetwork
my-app:
image: my-app-image
ports:
- "8000:80"
networks:
- mynetwork
networks:
mynetwork:
From the project folder, you run docker-compose up or docker-compose up -d to make the services run in the background.
In this scenario, the magic of Docker provisions a network with hostname "mynetwork". It should expose default ports to other services on that network. If you want to remap the ports, the pattern is target:source.
I don't know that you need the 'ports' config here. But I'm trying to map your config to the compose file. Also I'm assuming you need to expose the app on some port; using 8000 as it's pretty common setup.
What are the parameters here? Docker-compose reference

Connecting docker containers using external network

I am working on a micro-service architecture where we have many different projects and all of them connect to the same redis instance. I want to move this architecture to the Docker to run on development environment. Since all of the projects have separate repositories I can not just simply use one docker-compose.yml file to connect them all. After doing some research I figured that I can create a shared external network to connect all of the projects, so I have started by creating a network:
docker network create common_network
I created a separate project for common services such as mongodb, redis, rabbitmq (The services that is used by all projects). Here is the sample docker-compose file of this project:
version: '3'
services:
redis:
image: redis:latest
container_name: test_project_redis
ports:
- "6379:6379"
networks:
- common_network
networks:
common_network:
external: true
Now when I run docker-compose build and docker-compose up -d it works like a charm and I can connect to the redis from my local machine using 127.0.0.1:6379. But there is a problem when I try to connect to this redis container from an other container.
Here is an other sample docker-compose.yml for another project which runs Node.js (I am not putting Dockerfile since it is irrelevant for this issue)
version: '3'
services:
api:
build: .
container_name: sample_project_api
networks:
- common_network
networks:
common_network:
external: true
There is no problem when I build and run this docker-compose as well but the Node.js project is getting CONNREFUSED 127.0.0.1:6379 error, which obviously it can not connect to the Redis server over 127.0.0.1
So I opened a live ssh into the api container (docker exec -i -t sample_project_api /bin/bash) and installed redis-tools to make some tests.
When I try to ping the redis-cli ping it returns Could not connect to Redis at 127.0.0.1:6379: Connection refused.
I checked the external network to see if all of the containers are connected to it properly, using docker network inspect common_network. There were no problem, all of the containers were listed under Containers, and from there I noticed that sample_project_redis container had an ip address of 192.168.16.3
As a final solution I tried to use internal ip address of the redis container:
From sample_project_api container I run redis-cli -h 192.168.16.3 ping and it return with PONG which it worked.
So my problem is that I can not connect to the redis server from other containers using ip address of 127.0.0.1 or 0.0.0.0 but I can connect using 192.168.16.3 which changes every time I restart docker container. What is the reason behind this ?
Containers have a namespaced network. Each container has its own loopback interface and an ip for the container per network you attach to. Therefore loopback or 127.0.0.1 in one container is that container and not the redis ip. To connect to redis, use the service name in your commands, which docker will resolve to the ip of the container running redis:
redis:6379

Docker compose access to port on host

I'm running another docker-compose exposing Logstash on port 5044 (using docker-elk). I'm able to make requests to the service on localhost:5044 on my host, so the port is exposed correctly.
I'm then running another docker-compose (Filebeat) but from there I cannot connect to "localhost:5044". Here is the docker compose file:
version: '2'
services:
filebeat:
build: filebeat/
networks:
- elk
networks:
elk:
driver: bridge
Any cluye why the localhost:5044 is not accessable in this docker compose?
First of all, the compose file you linked exposes port 5000, but you say you're trying to connect to port 5044.
Secondly, exposing port 5044 (or 5000) will make the port available to the host machine, not to other containers launched with other compose files.
The way i see it is you can either:
keep the first service as it is and instead of localhost:port on the secon service use your_ip:port , where your_ip can be retrieved from ifconfig -a or something similar and should look like 192.168.x.x
Connect both services to an external created network like so:
first create the network with docker network create foo
link the services to the external network in the compose file:
networks:
test_network:
external: true
Then access change the logstash reference from localhost:port to logstash:port
Good luck

Resources