Docker: http requests from a container to other stalled - node.js

I use VPS for testing my web apps online. And I use Docker to run many web apps in the same server. Here is my
docker-compose.yml
version: "3.7"
services:
gateway:
build:
context: ./gateway
dockerfile: Dockerfile
restart: always
ports:
- 80:3000
networks:
erealm:
ipv4_address: 10.5.0.2
db:
image: mysql/mysql-server:5.5
restart: always
environment:
MYSQL_ROOT_PASSWORD: 4lf483t0
networks:
erealm:
ipv4_address: 10.5.0.3
phpmyadmin:
image: nazarpc/phpmyadmin:latest
environment:
- MYSQL_HOST=10.5.0.3:3306
restart: always
depends_on:
- db
ports:
- 1234:80
networks:
erealm:
ipv4_address: 10.5.0.4
static:
build:
context: ./static
dockerfile: Dockerfile
restart: always
networks:
erealm:
ipv4_address: 10.5.0.5
onlinecv:
build:
context: ./onlinecv
dockerfile: Dockerfile
restart: always
ports:
- 81:3000
networks:
erealm:
ipv4_address: 10.5.0.10
speeqapi:
build:
context: ./speeq/api
dockerfile: Dockerfile
restart: always
environment:
MYSQL_SERVER: 10.5.0.3
MYSQL_PORT: 3306
MYSQL_USER: xxxxxxxxxx
MYSQL_PASSWORD: xxxxxxxxxx
MYSQL_DATABASE: xxxxxxxxxx
depends_on:
- db
networks:
erealm:
ipv4_address: 10.5.0.20
speeqfe:
build:
context: ./speeq/fe
dockerfile: Dockerfile
restart: always
environment:
REACT_APP_API_SERVER: 10.5.0.20:3000
REACT_APP_STATIC_SERVER: 10.5.0.5:3000
ports:
- 82:3000
depends_on:
- db
- static
- speeqapi
networks:
erealm:
ipv4_address: 10.5.0.21
networks:
erealm:
driver: bridge
ipam:
config:
- subnet: 10.5.0.0/24
The main ideia behind this scheme is having only HTTP ports open to the world, while all necessary services run protected by Docker internal network, unaccesible to the world outside.
I use the gateway service to map the HTTP requests coming for the different apps to different ports. So, I have my online CV mapped to CNAME cv.eddealmeida.net and this Speeq app mapped to CNAME speeq.eddealmeida.net in my DNS zone, both pointing to this server. When my server receives a request to http://cv.eddealmeida.net or http://speeq.eddealmeida.net, the Node/Express-based gateway application (listening to port 80) splits the HOST paraments of the request an applies a simple mapping to send the requests to port 81 and 82 respectively.
Well, everything is running fine, but for the internal requests. First I had a problem with nternal name resolution, which I solved by giving IPs to all services, as you may see.
Now my internal requests are going to their correct places, but... the fetch requests made by the speeq frontend are stalling. They just keep stalling, over and over again. I tested the API using curl and everything is fine, it aswers correctly my command line requests. So, there is no problem with my API / Database connection or something like that. Google Chrome gave me this explanation, but I can't see me fitting in any of the cases mentioned.
Have someone ever lived a situation like this to give me a hint? I've been fighting this for the last 24 hours and run out of ideas. I double-checked everything and it still won't work.

I have few assumptions that might help.
1- Regarding the usage of IPs, I would suggest trying to use network aliases instead of IPs and this is a long-term solution
2- I can see that you are using ReactJS as a front-end which is a client side - I am assuming that you are using static files after building your React application - in this case you need to expose the backend/api to public ip through port mapping or using domain name points to a public ip where your api is listening or any similar method in order to make the front-end application able to reach it when you open it from the browser (which is a different device in your case). So if speeqfe is a reactjs frontend you need to change the environment variables value which points to the other containers to a public ip in order to make it work properly after building the static files

Related

SvelteKit SSR fetch() when backend is in a Docker container

I use docker compose for my project. It includes these containers:
Nginx
PostgreSQL
Backend (Node.js)
Frontend (SvelteKit)
I use SvelteKit's Load function to send request to my backend. In short, it sends http request to the backend container either on client-side or server-side. Which means, the request can be send not only by browser but also by container itself.
I can't get it to work on both client-side and server-side fetch. Only one of them is working.
I tried these URLs:
http://api.localhost/articles (only client-side request works)
http://api.host.docker.internal/articles (only server-side request works)
http://backend:8080/articles (only server-side request works)
I get this error:
From SvelteKit:
FetchError: request to http://api.localhost/articles failed, reason: connect ECONNREFUSED 127.0.0.1:80
From Nginx:
Timeout error
Docker-compose.yml file:
version: '3.8'
services:
webserver:
restart: unless-stopped
image: nginx:latest
ports:
- 80:80
- 443:443
depends_on:
- frontend
- backend
networks:
- webserver
volumes:
- ./webserver/nginx/conf/:/etc/nginx/conf.d/
- ./webserver/certbot/www:/var/www/certbot/:ro
- ./webserver/certbot/conf/:/etc/nginx/ssl/:ro
backend:
restart: unless-stopped
build:
context: ./backend
target: development
ports:
- 8080:8080
depends_on:
- db
networks:
- database
- webserver
volumes:
- ./backend:/app
frontend:
restart: unless-stopped
build:
context: ./frontend
target: development
ports:
- 3000:3000
depends_on:
- backend
networks:
- webserver
networks:
database:
driver: bridge
webserver:
driver: bridge
How can I send server-side request to docker container by using http://api.localhost/articles as URL? I also want my container to be accesible by other containers as http://backend:8080 if possible.
Use SvelteKit's externalFetch hook to have a different and overridden API URL in frontend and backend.
In docker-compose, the containers should be able to access each other by name if they are in the same Docker network.
Your frontend docker SSR should be able to call your backend docker by using the URL:
http://backend:8080
Web browser should be able to call your backend by using the URL:
(whatever reads in your Nginx configuration files)
Naturally, there are many reasons why this could fail. The best way to tackle this is to test URLs one by one, server by server using curl and entering addresses to the web browser address. It's not possible to answer the exact reason why it fails, because the question does not contain enough information, or generally repeatable recipe for the issue.
For further information, here is our sample configuration for a dockerised SvelteKit frontend. The internal backend shortcut is defined using hooks and configuration variables. Here is our externalFetch example.
From a docker compose you will be able to CURL from one container using the dns (service name you gave in the compose file)
CURL -XGET backend:8080
You can achieve this also by running all of these containers on host driver network.
Regarding the http://api.localhost/articles
You can change the /etc/hosts
And specify the IP you want your computer to try to communicate with when this url : http://api.localhost/articles is used.

I cannot establish connection between two containers in Heroku

I have a web application built using Node.js and MongoDB. I have containerized the app using Docker and it was working fine locally but once i have tried to deploy it to production I couldn't establish connection between the backend and MongoDB container. For some reason the environment variables are always undefined.
Here is my docker-compose.yml:
version: "3.7"
services:
food-delivery-db:
image: mongo:4.4.10
restart: always
container_name: food-delivery-db
ports:
- "27018:27018"
environment:
MONGO_INITDB_DATABASE: food-delivery-db
volumes:
- food-delivery-db:/data/db
networks:
- food-delivery-network
food-delivery-app:
image: thisk8brd/food-delivery-app:prod
build:
context: .
target: prod
container_name: food-delivery-app
restart: always
volumes:
- .:/app
ports:
- "3000:5000"
depends_on:
- food-delivery-db
environment:
- MONGODB_URI=mongodb://food-delivery-db/food-delivery-db
networks:
- food-delivery-network
volumes:
food-delivery-db:
name: food-delivery-db
networks:
food-delivery-network:
name: food-delivery-network
driver: bridge
This is expected behaviour:
Docker images run in dynos the same way that slugs do, and under the same constraints:
…
Network linking of dynos is not supported.
Your MongoDB container is great for local development, but you can't use it in production on Heroku. Instead, you can select and provision an addon for your app and connect to it from your web container.
For example, ObjectRocket for MongoDB sets an environment variable ORMONGO_RS_URL. Your application would connect to the database via that environment variable instead of MONGODB_URI.
If you'd prefer to host your database elsewhere, that's fine too. I believe MongoDB Atlas is the official offering.

Azure web app multi container (MEAN app), what is the URL to connect to node backend container from front end container?

Trying to learn to deploy angular app to azure web app using multi-container, the frontend loads fine but cant connect to the backend node container, I want to add the url of the node backend to my angular frontend but i cant figure out what it is. I've tried https://rojesh.azure.io:3000, https://rojesh.azurewebsites.net:3000, http://server:3000 and more but nothing seems to work. Website Hostname: https://rojesh.azurewebsites.net and the acr name is rojesh.azurecr.io which has 3 images. This is my config file for compose in azure:
version: '3.3'
services:
db:
image: rojesh.azurecr.io/db:latest
ports:
- "27017:27017"
restart: always
networks:
- app-network
server:
image: rojesh.azurecr.io/server:latest
depends_on:
- db
ports:
- "3000:3000"
restart: always
networks:
- app-network
app:
depends_on:
- server
image: rojesh.azurecr.io/app:latest
environment:
NGINX_HOST: rojesh.azurewebsites.net
NGINX_PORT: 80
ports:
- "80:80"
restart: always
networks:
- app-network
networks:
app-network:
driver: bridge
The app works fine locally using docker compose which is:
version: '3.9'
services:
docker-app:
build:
context: app
dockerfile: Dockerfile.dev
ports:
- '4200:4200'
volumes:
- ./app/src:/app/src
docker-server:
build:
context: server
dockerfile: Dockerfile
environment:
PORT: 3000
MONGODB_URI: mongodb://mongo:27017/rojesh
JWT_SECRET: secret
ports:
- 3000:3000
depends_on:
- mongo
volumes:
- ./server:/server
mongo:
container_name: mongo-server
image: mongo:latest
ports:
- 27017:27017
Thanks # ajkuma-msft. Azure App Service only exposes ports 80 and 443. Yes, incoming requests from client would just be over 443/80 which should be mapped to the exposed port of the container.
App Service will attempt to detect which port to bind to your container. If you want to bind to your container the WEBSITES_PORT app setting and configure it with a value of the port.
Web App for Containers currently allows you to expose only one port to the outside world. The container can only listen for HTTP requests on a single port.
From Docker compose configuration stand-point : Ports other than 80 and 8080 are ignored.
Refer Docker Compose options lists shows supported and unsupported Docker Compose configuration options.
Refer here

Can't access MongoDB container from NodeJS App

I'm running an instance of a web application in my Docker container and am also running a MongoDB container so when I launch the web app I can easily connect to the DB on the app's connection page.
The issue is that I'm not sure how to reach the Mongo container from my web app and am not sure if my host/port connection info is correct.
My Docker Setup
As you can see the container is up and running with both mongo and web app services running without errors
I build the two through docker-compose.yml
version: "3.3"
services:
web:
image: grafana-asw-v3
container_name: grafana-asw-v3
restart: always
build: .
ports:
- "13000:3000"
volumes:
- grafana-storage:/var/lib/grafana
stdin_open: true
tty: true
db:
container_name: mongo
image: mongo
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: example
volumes:
- grafana-mongo-db:/var/lib/mongo
ports:
- "27018:27017"
volumes:
grafana-mongo-db: {}
grafana-storage: {}
Issue
With everything up and running I'm attempting to connect through the web app, but I seem to be using the wrong connection info...
I assumed to use "hostMachine:port" (roxane:27018), but it's not connecting. Is there something I overlooked here?
There were two changes I had to make to fix this issue:
Modify the bind_ip in mongod.conf via making this change to my docker-compose file
db:
container_name: mongo
image: mongo
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: example
volumes:
- grafana-mongo-db:/var/lib/mongo
ports:
- "27018:27017"
command: mongod --bind_ip 0.0.0.0
I needed to refer to the IP address instead of the hostname in the cli in my we application. (Thanks to this answer for help with this one)
Short answer
db service is in the same network than web service not in host network.
As you named your services via container_name you shoud be able to use the connection string mongodb://mongo:27017
Explanation
By default, docker containers run under a bridge network allowing them to communicate without viewing your host network.
When using ports in a compose file, you define that you want to map an internal port of the container to the host port
"27018:27017" => I want to expose the container port number 27017 to the host port number 27018.
As a result, you could expose your web frontend without exposing your mongo service :
version: "3.3"
services:
web:
image: grafana-asw-v3
container_name: grafana-asw-v3
restart: always
build: .
ports:
- "13000:3000"
volumes:
- grafana-storage:/var/lib/grafana
stdin_open: true
tty: true
db:
container_name: mongo
image: mongo
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: example
volumes:
- grafana-mongo-db:/var/lib/mongo
volumes:
grafana-mongo-db: {}
grafana-storage: {}

Communication between microservices with docker-compose and traefik

I have a microservice based node app. I am using docker, docker-compose and traefik for service discovery.
I have 2 microservices at this moment:
the server app: running at node-app.localhost:8000
the search microservice running at search-microservice.localhost:8002
The issue I can't make a request from one microservice to another.
Here are my docker compose config:
# all variables used in this file are defined in the .env file
version: "2.2"
services:
node-app-0:
container_name: node-app
restart: always
build: ./backend/server
links:
- ${DB_HOST}
depends_on:
- ${DB_HOST}
ports:
- "8000:3000"
labels:
- "traefik.port=80"
- "traefik.frontend.rule=Host:node-app.localhost"
reverse-proxy:
image: traefik # The official Traefik docker image
command: --api --docker # Enables the web UI and tells Traefik to listen to docker
ports:
- "80:80" # The HTTP port
- "8080:8080" # The Web UI (enabled by --api)
volumes:
- /var/run/docker.sock:/var/run/docker.sock
search-microservice:
container_name: ${CONTAINER_NAME_SEARCH}
restart: always
build: ./backend/search-service
links:
- ${DB_HOST}
depends_on:
- ${DB_HOST}
ports:
- "8002:3000"
labels:
- "traefik.port=80"
- "traefik.frontend.rule=Host:search-microservice.localhost"
volumes:
node-ts-app-volume:
external: true
Both the node-app and the search-microservice expose the port 3000.
Why can't I call http://search-microservice.localhost:8002 from the node app ? calling it from the browser works though.
Because node-app is a container and to access other containers it has to use service name and internal port.
In your case it is search-microservice:3000.
To access host PC and exposed ports, you have to use host.docker.internal name for all services and external port.
If you want to access other services from in a different container with their hostnames, you can use the "extra_hosts" parameter in your docker-compose.yml file. Also, you have to use the "ipv4_address" parameter under the network parameter for each all services.
For example;
services:
node-app-1:
container_name: node-app
networks:
apps:
ipv4_address: 10.1.3.1
extra_hosts:
"search-microservice.localhost:10.1.3.2"
node-app-2:
container_name: search-microservice
networks:
apps:
ipv4_address: 10.1.3.2
extra_hosts:
"node-app.localhost:10.1.3.1"
Extra hosts in docker-compose

Resources