Docker Community Forums

Share and learn in the Docker community.

In multi container setup, failing to call service from another container while using Docker-Compose

I am using docker compose with multi container setup. I have an angular app, deployed on nginx and exposed to port 80. On second container, I am hosting .note core API, this service is returning a string.

In angular, I am calling URL http://localhost/api/values

Take a look at my attached docker compose.yml file. With my current set-up, when I hit localhost at port 81 in my local browser, I get the desired result.

But, in Angular app , rather than using “localhost”, I wanted to use “webapi”(http://webapi/api/values), I tried all sorts of options but I am not getting desired output. So far, I tried using hostname, container_name, aliases, etc

I would appreciate if you can point out my mistake here and help me to get desire output. Also, I would appreciate if you can suggest best option in case we run multiple instances on .net service.

Once this issues is solved, I am planning to deploy it on Azure, would I be needing any additional settings/configurations?

Here is my yml file

Thanks in advance.

version: '3.7'

services:
  web:
    build: hello
    container_name: web
    hostname: web
    image: jayforu/hello
    networks:
      backend:
         #aliases: 
          #  - web
      #   ipv4_address: 172.16.238.01

    ports:
      - 81:80
  webapi:
    build: HelloApi
    container_name: webapi
    hostname: webapi
    image: jayforu/helloapi
    networks:
      backend:
         #aliases: 
          #  - webapi
        #ipv4_address: 172.16.238.02
    ports:
      - 80:80
networks:
  backend:
   # ipam:
      driver: bridge
    #  config:
     #   - subnet: "172.16.238.0/24"

Alias, hostname, and container_name are useless here : the service name should be enough.
Your “web” container should be able to see a ‘webapi’ host (using docker dns system).
You can check what names a docker network provide using :

docker network inspect backend -f '{{json .Containers}}'|jq .

(if you dont have jq installed, then just docker network inspect backend would suffice, jq is used here only for prettyfication)
Then connect to your web container, and verify that it does indeed know that it does indeed know “webapi”

docker exec -it <id> nslookup webapi

On an unrelated note, if you dont want anyone accessing the webapi, then you dont need to set ports : all the ports are open within the docker network.

Thanks a lot @sebt3.

I will try this today.

@sebt3: Pardon my ignorance but If I remove port numbers from the application, how can I make it work? Could you please guide me here? If I want to set up a production environment, how should I do it? I want to try similar set up, going to call .net api from angualr container.

You must have notice that I am novice here , so, I would highly appreciate if you can invest some time in answering this in detail.

I dont know for your apps, but most apps only have one point of entry.
My typical deploiement is using the following containers nginx, php, redis and postgreSQL. I only publish the nginx port using the ports keyword. Nginx can acces the php container using the private network set up (just like yours in your compose file). And then the php container access the redis and postgres databases using the same network.

If your users access both web and webapi containers directtly, then leave it as it is. But if they only access directly the web container and then the web container talk to the webapi, then dont publish the webapi port.
And if you dont publish your webapi port, then the port number 80 become free to use for your angular (web) container :wink:

To sum it up, this compose file should be sufficent :

version: '3.7'
services:
  web:
    build: hello
    image: jayforu/hello
    networks:
      backend:
    ports:
      - 80:80
  webapi:
    build: HelloApi
    image: jayforu/helloapi
    networks:
      backend:
networks:
  backend:

And if it isnt, then I would suggest to re-read your angular code as you might have forgot some hardcoded query to localhost :wink:

Thanks for your prompt reply, I did all that you asked before you sharing this new yml file. I changed url in Angular app to “http://webapi/api/values” but still it didnt produce the output I expected.

I am sharing link to public repo of this dummy project, https://github.com/jayrajvcybage/dockercompose.git
if you can take a look at it, it would be really helpful. I created logs folder to show you network info and my steps for building project. URL is getting consumed in file hello-world.service.ts.

Thanks in advance

And on my browser, I was hitting localhost. @sebt3, kindly find some time to take a look at that git repo

In that network, your webapi container is known as such as per line 36.

I cant read angular code, sorry.
Have a look at the logs generated by your “web” container (docker logs <container id>)

@sebt3 Thanks for your time, I will see if I made any mistake in Angular routing or nginx configuration

It took me a couple of months to figure out how to compose containers in Docker, and have each container on a certain network and how to call services from them. I was looking at your compose file and I can see you don’t understand the networking part.

This is my .Net Core project, I have Angular wrapped inside it, and I call nothing but controller services from the Core wrapper.

I got caught up in assigning IP Addresses at first, and getting complicated with networking. And then I realized that I only had to assign an IP Address to the container that faces the public, and the rest can be self assigned by Docker. You do have to assign port numbers however.

I didn’t use nginx, and used the built-in webserver in .Net Core called Kestrel. You program Kestrel in Programs.CS, define your SSL, ports, rules, etc. Kestrel is wicked fast, and I can control the hosting environment in the project code.

But to get it right, so it’s works in development and production environments, you have to create each container one at a time. It’s very time consuming to start, but once you create the first container, say the database, then you go to the next container and try to talk to it. When you get 2 or 3 containers going, it gets easier.

The host network faces the public. Then you have an overlay network that all the other containers use to talk to each other. Docker will set these up automatically, and you just use container names to link up to them.

version: ‘3.7’

services:
jkirkerx:
container_name: jkirkerx
image: jkirkerx/website:v330
restart: unless-stopped
depends_on:
- mongo
environment:
- ASPNETCORE_URLS=https://+:443;http://+:80
- ASPNETCORE_HTTPS_PORT=443
- ASPNETCORE_ENVIRONMENT=Production
- PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
- DOTNET_RUNNING_IN_CONTAINER=true
- ASPNETCORE_VERSION=2.2.4
- ASPNETCORE_OPTIMIZE=true
ports:
- 192.168.3.9:80:80/tcp
- 192.168.3.9:443:443/tcp
- 5001:5001
networks:
- host
- overlay
volumes:
- jkirkerx-root:/wwwroot/content
logging:
driver: json-file

mongo:
image: mongo:latest
container_name: mongo
restart: unless-stopped
environment:
- MONGO_INITDB_ROOT_USERNAME=xxxxxx
- MONGO_INITDB_ROOT_PASSWORD=xxxxxx
- MONGO_INITDB_DATABASE=xxxxxx
- MONGO_DATA_DIR=/data/db
- MONGO_LOG_DIR=/dev/logs
volumes:
- data-volume:/data/db
- ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro
ports:
- 27017:27017
environment:
- MONGODB_EXTRA_FLAGS=–wiredTigerCacheSizeGB=2
networks:
- overlay
command: mongod --auth --serviceExecutor adaptive --enableFreeMonitoring off

volumes:
data-volume:
name: mongoData
external: false
jkirkerx-root:
name: jkirkerxContent
external: false

networks:
host:
overlay: