I'm currently trying to host two of my asp.net core services in docker. I am able to get them both up and running but the problem is that I don't know how to communicate between the two containers.
I'm using docker-compose to get my applications up and running and to allocate the ports on my host machine.
The urls to the services are placed in the appsettings.json. I think the problem lies here because I don't know where to get the right IP of the running containers.
I already tried to use the host network in both docker-compose files but I wasn't able to get that working.
I also tried to get the container's IP by using docker container inspect. but those IP's are unreachable.
docker-compose of service 1:
version: '3.4'
services:
leave.api:
build:
context: .
dockerfile: app1/Dockerfile
environment:
- ASPNETCORE_ENVIRONMENT=Development
ports:
- 5002:5002
docker-compose of service 2:
version: '3.4'
services:
backoffice:
build:
context: .
dockerfile: BackOffice/Dockerfile
environment:
- ASPNETCORE_ENVIRONMENT=Development
ports:
- 5001:5001
I hope to find a way to be able to communicate between the two services.
You could use external_links options, seems the most fit solution in your case:
https://docs.docker.com/compose/compose-file/#external_links
This explains bridging containers https://docs.docker.com/v17.09/engine/userguide/networking/default_network/container-communication/
If your communication is http based I would recommend having a http gateway that keeps track of your containers and their service endpoints.
You can communicate between two services in docker container using the name of service.
In your case, you have backoffice and leave.api services in your docker composed file.
So, you can access the backoffice service from leave.api using https://backoffice:5001/.
Thanks for all the answers, but I found another solution that works best for my situation.
I added the following line to both of my docker-compose files:
network_mode: bridge
This way both of my containers use the same network. After that I could communicate between the containes using my host ip address with the port the service is bound to. I placed this IP in the appsettings.json the same way as I had it before.
Related
I'm very new to Docker (in fact I've been only using it for one day) so maybe I'm misunderstanding some basic concept but I couldn't find a solution myself.
Here's the problem. I have an ASP.NET Core server application on a Windows machine. It uses MongoDB as a datastore. Everything works fine. I decided to pack all this stuff into Docker containers and put it to a Linux (Ubuntu Server 18.04) server. I've packed mongo to a container so now its PUBLISHED IP:PORT value is 192.168.99.100:32772
I've hardcoded this address to my ASP.NET server and also packed it to a container (IP 192.168.99.100:5000).
Now if I run my server and mongo containers together on my Windows machine, they work just fine. The server connects to a container with the database and can do whatever it needs.
But when I transfer both containers to Ubuntu and run them, the server cannot connect to the database because this IP address is not available there. I've beed googling for a few hours to find a solution and still I'm struggling with it.
What is the correct way to go about thes IP addresses? Is it possible to set an IP that will be the same for a container regardless of environment?
I recommend using docker-compose for the purpose you described above.
With docker-compose, you can access the database via a service name instead of an IP (which potentially is not available on another system). Here two links to get started
https://docs.docker.com/compose/gettingstarted/
https://docs.docker.com/compose/compose-file/
Updated answer (10.11.2019)
Here a concrete example for your asp.net app:
docker-compose.yaml
version: "3"
services:
frontend:
image: fqdn/aspnet:tag
ports:
- 8080:80
links:
- database
database:
image: mongo
environment:
MONGO_INITDB_DATABASE: "mydatabase"
MONGO_INITDB_ROOT_USERNAME: "root"
MONGO_INITDB_ROOT_PASSWORD: "example"
volumes:
- myMongoVolume:/data/db
volumes:
myMongoVolume: {}
From the frontend container, you can reach the mongo db container via the service name "database" (instead of an IP). Due to the link definition in the frontend service, the frontend service will start after the linked service (database).
Through volume definition, the mongo database will be stored in a volume that persists independently from the container lifecycle.
Additionally, I assume you want to reach the asp.net application via the host IP. I do not know the port that you expose in your application so I assume the default port 80. Via the ports section in the frontend, we define that container port 80 is exposed as port 8080 on the host IP. e.g. you can open your browser and type your host IP and port 8080 e.g. 127.0.0.1:8080 for localhost and reach your application.
With docker-compose installed, you can start your app, which consists of your frontend and database service via
docker-compose up
Available command options for docker-compose can be found here
https://docs.docker.com/compose/reference/overview/
Install instructions for docker-compose
https://docs.docker.com/compose/install/
Updated answer (10.11.2019, v2)
From the comment section
Keep in mind that you need to connect via the servicename (e.g. database) and the correct port. For MongoDB that port is 27017. That would tanslate to database:27017 in your frontend config
Q: will mongo also be available from the outside in this case?
A: No, since the service does not contain any port definition the database itself will not be directly reachable. From a security standpoint, this is preferable.
Q: could you expain this
volumes:
myMongoVolume: {}
A: in the service definition for your database service, we have specified a volume to store the database itself to make the data independent from the container lifecycle. However just by defining a volume in the service section the volume will not be created. Through the definition in the volume section, we create the volume myMongoVolume with the default settings (indicated through {}). If you would like to customize your volume you can do so in this volumes section of your docker-compose.yaml. More information regarding volumes can be found here
https://docs.docker.com/compose/compose-file/#volume-configuration-reference
e.g. if you would like to use a specific storage driver for your volume or use an external storage.
I am pretty much new to the docker concept and know basics of it.
I just wanted to know how can we build multi tenant application using docker.
Where the containers will use the local hosted database with different schema.With the nginx we can do reverse proxy but how we can achieve it?
because every container will be accessed by localhost:8080 and how we can add upstream and server part.
It will be very helpful if some one explains it to me.
If I understand correctly you want processes in containers to connect to resources on the host.
From you containers perspective in bridge mode (the default), the host's IP is the gateway. Unfortunate the gateway IP address may vary and can only be determinate at runtime.
Here are a few ways to get it:
From the host using docker inspect: docker inspect <container name or ID>. The gateway will be available under NetworkSettings.Networks.Gateway.
From the container you can execute route | awk '/^default/ { print $2 }'
One other possibility is to use --net=host when running your container.
This will run you processes on the same network as your processes on your host. Doing so will make your database accessible from the container on localhost.
Note that using --net=host will not work on Docker for mac/windows.
I am using docker-compose to run an application on the bluemix container service. I am using nginx as a proxy webserver and load balancer.
I have found an image that uses docker events to automatically detect new web servers and adds those to the nginx configuration dynamically:
https://github.com/jwilder/nginx-proxy
But for this to work, I think the container needs to connect to a docker socket. I am not very familiar with docker and I dont know exactly what this does, but essentially it is necessary so that the image can listen to docker events.
The run command from the image documentation is the following:
docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
I have not been able to run this in the container service, as it does not find the /var/run/docker.sock file on the host.
The bluemix documentation has a tutorial explaining how to do load balancing with nginx. But it requires a "hard coded" list of web servers in the nginx configuration.
I was wondering how I could run the nginx-proxy image so that web instances are detected automatically?
The containers service on Bluemix doesn't expose that docker socket (not surprising, it would be a security risk to the compute host). A couple of alternate ways to accomplish what you want:
something like amalgam8 or consul, which is basically doing just that
similar, but self written - have a shared volume, and then each
container on startup adds a file to that shared volume saying what it
is, plus its private ip. nginx container has a watch on the shared
volume, and reloads when those change. (more work than amalgam8 or
consul, but perhaps more control)
I am currently running a development stack using Docker-Compose in my company, to provide to developers everything they need to code our applications.
It includes in particular:
a Gitlab container (sameersbn/gitlab) to manage private GIT repositories,
a Jenkins container (library/jenkins) for building and continuous integration,
an Archiva container (ninjaben/archiva-docker) to manage Maven repositories.
In order to secure the services through HTTPS, and exposing them to the outside world, I installed the excellent nginx-proxy container (jwilder/nginx-proxy) which allows automated nginx proxy configuration using environment variables on containers, and automated HTTP to HTTPS redirection.
DNS are configured to map each public URL of dockerized services to the IP of the host.
Finally, using Docker-Compose, my docker-compose.yml file looks like this :
version: '2'
services:
nginx-proxy:
image: jwilder/nginx-proxy
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- /var/config/nginx-proxy/certs:/etc/nginx/certs:ro
postgresql:
# Configuration of postgresql container ...
gitlab:
image: sameersbn/gitlab
ports:
- "10022:22"
volumes:
- /var/data/gitlab:/home/git/data
environment:
# Bunch of environment variables ...
- VIRTUAL_HOST=gitlab.my-domain.com
- VIRTUAL_PORT=80
- CERT_NAME=star.my-domain.com
archiva:
image: ninjaben/archiva-docker
volumes:
- /var/data/archiva:/var/archiva
environment:
- VIRTUAL_HOST=archiva.my-domain.com
- VIRTUAL_PORT=8080
- CERT_NAME=star.my-domain.com
jenkins:
image: jenkins
volumes:
- /var/data/jenkins:/var/jenkins_home
environment:
- VIRTUAL_HOST=jenkins.my-domain.com
- VIRTUAL_PORT=8080
- CERT_NAME=star.my-domain.com
For a developer workstation, everything works as expected. One can access the difference services through https://gitlab.my-domain.com, https://repo.my-domain.com and https://jenkins.my-domain.com.
The problem occurs when one of the dockerized service access another dockerized service. For instance, If I try to access https://archiva.my-domain.com from jenkins docker, I will get a timeout error from the proxy.
It seems that even if archiva.my-domain.com is resolved as the public host IP from the docker container, requests coming from dockerized services are not proxied by nginx-proxy.
As far as I understood, docker-nginx is handling requests coming from the host network, but does not care about the ones coming from the internal container network (_dockerconfig_default_ for a Docker-Compose stack).
You could say, why would I need to use the proxy from a container ? Of course, I could use URL http://archiva:8080 from Jenkins container, and it would work. But this kind of configuration is not scalable.
For example, using a Gradle build to compile one application, the build.gradle needs to declare my private repository through https://archiva.my-domain.com. It will work if build is launched from a developer workstation, but not through the jenkins container ...
Another example is an authentication in Jenkins by OAuth GitLab service, where the same URL GitLab authentication needs to be both available from the outside, and inside the Jenkins container.
My question here is then : How to configure nginx-proxy to proxy a request from a container to another container ?
I did not see any topic discussing this problem, and I do not understand enough the problem to build a solution on nginx configuration.
Any help would be really appreciated.
BMitch, the odds were good, it was indeed a iptables rules problem, and not a misconfiguration of nginx-proxy.
The default policy of chain INPUT for the table filter was DROP, and no rules was made to ACCEPT requests from the container IPs (127.20.X.X).
So for the record, I give some details of the situation if other people face the same problem.
To access containers from the outside world, Docker put rules on PREROUTING and FORWARD rules to allow external IPs to be DNATed from the host IP to the container IPs. Theses default rules allow any external IPs, and that is why limiting access to containers requires some advanced iptables customizations.
See this link for an example : http://rudijs.github.io/2015-07/docker-restricting-container-access-with-iptables/
But if your containers need to access host resources (services runing on the host, or in my case, a nginx-proxy container listening to HTTP/HTTPS host port and proxying to containers), you need to take care about the iptables rules of the INPUT chain.
In fact, a request coming from the container and addressed to the host will be routed to the host network stack by the Docker daemon, but will then need to pass the INPUT chain (as the request src IP is the host one). So if you want to protect host resources and let containers access them, do not remember to add something like this :
iptables -A INPUT -s 127.20.X.X/24 -j ACCEPT
Where 127.20.X.X/24 is the virtual network on which your containers are running.
Thank you a lot for your help.
I think this may be an XY problem, so I'll include the context of the question since I don't know the best way to solve this problem.
I have a kubernetes environment set up on AWS such that I have two parts, an nginx container, and a backend service (which I'll call SvcA). Since the backend service can come and go, in my nginx config I have something that looks like:
resolver kube-dns.kube-system.svc.cluster.local valid=60s ipv6=off;
server {
# stuff
location / {
set $backend "SvcA.default.svc.cluster.local:8000";
proxy_pass http://$backend;
}
}
This setup works well on kubernetes, but I want a way have having the (almost) exact same set up on my local machine for testing/development but without all the overhead of using kubernetes. What I want to do is stick these two containers (nginx, SvcA) into a docker-compose file and have it working that way. The problem I've run into, is that the resolver for the nginx is hard-coded to be the url on kubernetes, and the solution I think may work is to have container that is a dns, and it's sole entry is to point "SvcA.default.svc.cluster.local" to the name docker-compose assigns.
I'm unsure if this is the best way to solve the problem, and if it is, I don't know enough about DNS configuration to set this up. Is this the best solution to my problem, and if so, how would I configure a dns server to handle this?
i am not sure if you need a dns.
you can do something like this, even if the URL is hardcoded
eg docker-compose.yml
version: '2'
services:
service1:
...
networks:
back-tier:
ipv4_address: "172.16.238.10"
service2:
...
networks:
back-tier:
ipv4_adress: "172.16.238.11"
networks:
back-tier:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.16.238.0/24
gateway: 172.16.238.1
you can even set hostnames for each container, etc, you could also make a link between them. if you need it to be circular you can do it with extra_hosts parameter.
if should be able to find all the info you need over here:
https://docs.docker.com/compose/compose-file/
if the containers are on the same network they should be able to talk to each other