Docker web app can't communicate with API app - docker

I have 2 .net core apps running in docker (one is a web api, the other is a web app consuming the web api):
I can't seem to communicate with the api via the web app, but I can access the api by going directly to it in my browser at http://localhost:44389
I have an environment variable in my web app that has that same info, but it can't get to it.
If I were to specify the deployed version of my API on azure, it's able to communicate with that address. Seems like the problem is the containers talking to each other.
I read that creating a bridge should fix that problem but it doesn't seem to. What am I doing wrong?
Here is my docker compose file:
version: '3.4'
services:
rc.api:
image: ${DOCKER_REGISTRY}rcapi
build:
context: .
dockerfile: rc.Api/Dockerfile
ports:
- "44389:80"
rc.web:
image: ${DOCKER_REGISTRY}rcweb
build:
context: .
dockerfile: rc.Web/Dockerfile
environment:
- api_endpoint=http://localhost:44389
depends_on:
- rc.api
networks:
my-net:
driver: bridge

docker-compose automatically creates a network between your containers. As your containers are in the same network you would be able to connect between containers using aliases. docker-compose creates an alias with the container name and the container IP. So in your case docker-compose should look like
version: '3.4'
services:
rc.api:
image: ${DOCKER_REGISTRY}rcapi
build:
context: .
dockerfile: rc.Api/Dockerfile
ports:
- "44389:80"
rc.web:
image: ${DOCKER_REGISTRY}rcweb
build:
context: .
dockerfile: rc.Web/Dockerfile
environment:
- api_endpoint=http://rc.api
depends_on:
- rc.api
networks:
my-net:
driver: bridge
As in rc.api opens port 80 in its container, therefore rc.web can access to 80 port with http://rc.api:80 or http://rc.api (without port since HTTP port is default 80)

You need to call http://rc.api because you have two containers and the API containers localhost is different from the web apps container localhost.
The convention is each service can be resolved by its name specified in the docker-compose.yml.
Thus you can call the API on internal Port 80 instead of exposing it on a particular port.

Related

Docker compose a Server API and Nuxt Client?

I'm trying since 2 weeks to make a docker compose that link an api server (strapi) and a Nuxt app (client)
Nuxt make request to the api server to get data. But I don't know how to make them communicate to share data and make request.
I tried a lot of config but don't work.
My docker-compose.yml:
version: "3.9"
services:
client:
image: nuxt-client
networks:
- my-network
environment:
STRAPI_URL: server:4040
depends_on:
- server
server:
image: strapi-server
networks:
- my-network
volumes:
- ./data:/app/.tmp/
networks:
my-network:
driver: bridge
I try my nuxt app to make a request on the server with the port 4040
In environment, nuxt app take STRAPI_URL which is the url of the api (example: http://localhost:4040)
But the request on the network tab is 404
I want to put this docker compose in my nginx proxy manager, and i don't want to make port outside containers.
Any help ? :)

docker compose pushing to docker hub

I have a docker-compose file which has 3 services, the yaml file works but how do i push this into registry as a single image and retrieve this is AWS Fargate so it spins up container ?
What are my options to spin up multiple containers as images are pushed into separate repositories.
This below is my Docker-compose.yaml file
version: '3.4'
services:
dataapidocker:
image: ${DOCKER_REGISTRY-}dataapidocker
build:
context: .
dockerfile: DataAPIDocker/Dockerfile
environment:
- DB_PW
depends_on:
- db
db:
image: mcr.microsoft.com/mssql/server
environment:
SA_PASSWORD: "${DB_PW}"
ACCEPT_EULA: "Y"
ports:
- "1433:1433"
proxy1:
build:
context: ./proxy
dockerfile: Dockerfile
restart: always
depends_on:
- dataapidocker
ports:
- "9999:80"
The method which i tried was creating two application
First application : A nodejs express api server running at port 3001 with axios also attached
Second Application : A nodejs express api server running at port 3010 with /data(can be anything) path to return some data, with cross origin access allowed.
What i did was from first application, using axios.get command i queried localhost:3010/data to and printed it.
Now create a separate dockerfile image of both.When you run them they might not work as they are querying the localhost.
Create a taskdefinition into awsfargate and launch the task. Access the public IP of first container you will be able to receive the data from the second container just by querying the localhost, as fargate has them in the same network.
If you want the code i can share them.

Two docker containers cannot communicate

I have two docker containers. One container is a database and the other is a web application.
Web application calls the database through this link http://localhost:7200. However, the web application docker container cannot reach the database container.
I tried this docker-compose.yml, but does not work:
version: '3'
services:
web:
# will build ./docker/web/Dockerfile
build:
context: .
dockerfile: ./docker/web/Dockerfile
links:
- graph-db
depends_on:
- graph-db
ports:
- "8080:8080"
environment:
- WAIT_HOSTS=graph-db:7200
networks:
- backend
graph-db:
# will build ./docker/graph-db/Dockerfile
build:
./docker/graph-db
hostname: graph-db
ports:
- "7200:7200"
networks:
backend:
driver: "bridge"
So I have two containers:
web application: http://localhost:8080/reasoner and this container calls a database in http://localhost:7200 which resides in a different container.
However database container is not reachable by web container.
SOLUTION
version: '3'
services:
web:
# will build ./docker/web/Dockerfile
build:
context: .
dockerfile: ./docker/web/Dockerfile
depends_on:
- graph-db
ports:
- "8080:8080"
environment:
- WAIT_HOSTS=graph-db:7200
graph-db:
# will build ./docker/graph-db/Dockerfile
build:
./docker/graph-db
ports:
- "7200:7200"
and replace http://localhost:7200 in web app code with http://graph-db:7200
Do not use localhost to communicate between containers. Networking is one of the namespaces in docker, so localhost inside of a container only connects to that container, not to your external host, and not to another container. In this case, use the service name, graph-db, instead of localhost, in your app to connect to the db.
Your db host is graph-db, and that name that you should use in database configuration in your app. eg: http://graph-db:7200
From docker network documentation (bridge networks - the default network driver in Docker):
Imagine an application with a web front-end and a database back-end.
If you call your containers web and db, the web container can connect
to the db container at db, no matter which Docker host the application
stack is running on.

Conusume API from a client docker container to the server container

I have two different projects running on different docker containsers. Below the two YML files:
FILE webserver-api/docker-compose.yml
version: "3.1"
services:
webserver:
image: nginx:alpine
container_name: webserver-api
working_dir: /application
volumes:
- .:/application
- ./docker/nginx/nginx.conf:/etc/nginx/conf.d/default.conf
ports:
- "8005:80"
FILE client-app/docker-compose.yml
version: '3'
services:
web:
container_name: client-app
build:
context: ./
dockerfile: deploy/web.docker
volumes:
- ./:/var/www
ports:
- "8010:80"
links:
- app
app: [...]
database: [...]
From the client-app I would like to call the webserver-api.
When I'm trying to consume the API from webserver-api I'm getting the message "cURL error connection refused" or timeout error.
For example
$response = file_get_contents('http:/localhost:8005/api/test');
I tried also to replace the localhost with the IP of the webserver-api container like this:
$response = file_get_contents('http://172.25.0.2:8005/api/test');
But still I get a timeout connection error.
Which is the correct URL of the server container to call form the client container? Or how to set the host URL?
Thanks a lot for the help and time.
You need create a network first. Then use this network for both your client and server docker compose. Otherwise the network is isolated.
Another approach is expose the port of server to localhost and connect to localhost from client side.
As per the docker-compose documentation
By default Compose sets up a single network for your app. Each container for a service joins the default network and is both reachable by other containers on that network, and discoverable by them at a hostname identical to the container name.
So ideally if your service are interdependent you should put them in a single compose file. In that case you could have accessed your service directly by name and container port
http://webserver/api/test
But since they are in separate compose file, you can access the service via host mapped port
$response = file_get_contents('http://localhost:8005/api/test');
it should also work.
To debug you can check
If port binding to 8005 is happening on your host.
The endpoint specified is correct and accessible from host.
Finally I figured it out.
By default docker creates a network called (in my case) webserver-api_default where webserver-api is the name of the folder that contains the YML file [projectname]_default.
On the client-app/docker-compose.yml of the client I had to specify which network to join:
version: '3'
networks:
default:
external:
name: webserver-api_default
web:
container_name: client-app
build:
context: ./
dockerfile: deploy/web.docker
volumes:
- ./:/var/www
ports:
- "8010:80"
links:
- app
app: [...]
database: [...]
And from the client container I have to make the call to the URL:
$response = file_get_contents('http://webserver-api:8005/api/test');
Where webserver-api is the name of the server container and not the name of the network.
https://docs.docker.com/compose/networking/

How to connect frontend to backend via docker-compose networks

I'm trying to dockerize my angular + express application. I have a docker-compose file that creates the two containers, and I am able to hit the containers from my host machine(using my browser), but I'll just get a "ERR_NAME_NOT_RESOLVED" whenever I try to hit the backend from http requests made by my frontend.
I've looked up the issue, and it seems like most suggest that the service name and container port should be enough to hit the the other container when they're on the same network. I've tried to hit "http://express:8000/user?user=030f0e70-9a8f-11e9-b5d1-f5cb6c0f3616" which I think should work given what I've seen from other places, but regardless, I get the same error.
My docker-compose file looks like
version: '3' # specify docker-compose version
# Define the services/containers to be run
services:
angular: # name of the first service
build: ./ # specify the directory of the Dockerfile
ports:
- "4200:80" # specify port forewarding
links:
- "express"
depends_on:
- "express"
express: #name of the second service
build: # specify the directory of the Dockerfile
context: ./
dockerfile: dockerfile.be
ports:
- "8000:8000" #specify ports forewarding
expose:
- "8000"
Ideally, I'd like my frontend to be able to hit the other container with a set endpoint, so I could deploy the application with minimal changes. I'd appreciate any advice. I feel like I'm missing something really simple, but after a few hours of tinkering, I still haven't caught it.
Thanks!
In fact your traffic is as next:
User browser request page from angular container, then all pages will rendered to user's browser.
The front javascript code using angular HttpClient to fetch the data from express container.
At that time, although docker-compose setup a customized network for you which afford auto-dns to resolve angular & express, but this dns just works among containers, not effect for host.
But, your augular HttpClient which call http://express was happened on user's browser which not in container, so the auto-dns defintly not work for you to resolve the name express.
For you, if you just want to open browser from your docker host, you can use localhost, but if you also want the user from other machine to visit your web, you had to use the ip of your dockerhost.
Then, in angular HttpClient you need to use something like http://your_dockerhost_ip:8000 to visit express container.
If interested, you can visit this to see User-defined bridges provide automatic DNS resolution between containers.
A few things:
By using expose, you are making the container's published ports only available to linked/networked services. This is one reason why you are unable to access it locally.
Instead of hitting http://express:8000/ you should try to hit http://localhost:8000. The service is being published to your localhost system and is not being served by anything by default (e.g., IIS, NGINX).
Add a custom defined network in your compose file instead of using links. This is now the main way to network containers together:
version: '3' # specify docker-compose version
services:
angular: # name of the first service
build: ./ # specify the directory of the Dockerfile
ports:
- "4200:80" # maps port 4200 on localhost to 80 in container
network:
- mynetwork
depends_on:
- "express"
express: # name of the second service
build: # specify the directory of the Dockerfile
context: ./
dockerfile: dockerfile.be
ports:
- "8000:8000" # maps port 8000 on localhost to 8000 in container
networks:
- mynetwork
networks:
mynetwork:
2: https://docs.docker.com/compose/compose-file/#expose
**sample docker-compose.yaml**
version: '3.5'
services:
angular:
image: "angular-alpine:0.0.1"
container_name: angular
tty: true
stdin_open: true
networks:
app_net:
ipv4_address: 172.16.238.05
depends_on:
- express
express:
image: "express:0.0.1"
container_name: express
tty: true
stdin_open: true
networks:
app_net:
ipv4_address: 172.16.238.10
networks:
app_net:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.16.238.0/24
>"1. Angular will run on 172.16.238.05:4200 and express will run on 172.16.238.10:some-port.
2. modify your config.ts or parameter.ts or anyfile where you configure express url into 172.16.238.10:some-port. now your angular will connect to express."

Resources