Docker - SequelizeConnectionRefusedError: connect ECONNREFUSED 127.0.0.1:3306 - node.js

I'm trying to get my nodejs application up and running using a docker container. I have no clue what might be wrong. The credentials seems to be passed correctly when I debug the credentials with the console. Also firing up sequel pro and connecting directly with the same username and password seems to work. When node starts in the container I get the error message:
SequelizeConnectionRefusedError: connect ECONNREFUSED 127.0.0.1:3306
The application itself is loading correctly on port 3000, however no data is retrieved from the database. If have also tried adding the environment variables directly to the docker compose file, but this also doesn't seem to work.
My project code is hosted over here: https://github.com/pietheinstrengholt/rssmonster
The following database.js configuration is used. When I add console.log(config) the correct credentials from the .env file are displayed.
require('dotenv').load();
const Sequelize = require('sequelize');
const fs = require('fs');
const path = require('path');
const env = process.env.NODE_ENV || 'development';
const config = require(path.join(__dirname + '/../config/config.js'))[env];
if (config.use_env_variable) {
var sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
var sequelize = new Sequelize(config.database, config.username, config.password, config);
}
module.exports = sequelize;
When I do a console.log(config) inside the database.js I get the following output:
{
username: 'rssmonster',
password: 'password',
database: 'rssmonster',
host: 'localhost',
dialect: 'mysql'
}
Following .env:
DB_HOSTNAME=localhost
DB_PORT=3306
DB_DATABASE=rssmonster
DB_USERNAME=rssmonster
DB_PASSWORD=password
And the following docker-compose.yml:
version: '2.3'
services:
app:
depends_on:
mysql:
condition: service_healthy
build:
context: ./
dockerfile: app.dockerfile
image: rssmonster/app
ports:
- 3000:3000
environment:
NODE_ENV: development
PORT: 3000
DB_USERNAME: rssmonster
DB_PASSWORD: password
DB_DATABASE: rssmonster
DB_HOSTNAME: localhost
working_dir: /usr/local/rssmonster/server
env_file:
- ./server/.env
links:
- mysql:mysql
mysql:
container_name: mysqldb
image: mysql:5.7
command: --default-authentication-plugin=mysql_native_password
environment:
MYSQL_RANDOM_ROOT_PASSWORD: "yes"
MYSQL_DATABASE: "rssmonster"
MYSQL_USER: "rssmonster"
MYSQL_PASSWORD: "password"
ports:
- "3307:3306"
volumes:
- /var/lib/mysql
restart: unless-stopped
healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
timeout: 5s
retries: 10
volumes:
dbdata:
Error output:
{ SequelizeConnectionRefusedError: connect ECONNREFUSED 127.0.0.1:3306
app_1 | at Promise.tap.then.catch.err (/usr/local/rssmonster/server/node_modules/sequelize/lib/dialects/mysql/connection-manager.js:128:19)
app_1 | From previous event:
app_1 | at ConnectionManager.connect (/usr/local/rssmonster/server/node_modules/sequelize/lib/dialects/mysql/connection-manager.js:125:13)
app_1 | at sequelize.runHooks.then (/usr/local/rssmonster/server/node_modules/sequelize/lib/dialects/abstract/connection-manager.js:306:50)
app_1 | From previous event:
app_1 | at ConnectionManager._connect (/usr/local/rssmonster/server/node_modules/sequelize/lib/dialects/abstract/connection-manager.js:306:8)
app_1 | at ConnectionManager.getConnection (/usr/local/rssmonster/server/node_modules/sequelize/lib/dialects/abstract/connection-manager.js:247:46)
app_1 | at Promise.try (/usr/local/rssmonster/server/node_modules/sequelize/lib/sequelize.js:564:34)
app_1 | From previous event:
app_1 | at Promise.resolve.retryParameters (/usr/local/rssmonster/server/node_modules/sequelize/lib/sequelize.js:464:64)
app_1 | at /usr/local/rssmonster/server/node_modules/retry-as-promised/index.js:60:21
app_1 | at new Promise (<anonymous>)

Insteaf of localhost point to mysql which is the service name (DNS) that nodejs will resolve into the MySQL container:
DB_HOSTNAME: mysql
And
{
...
host: 'mysql',
...
}

Inside of the container you should reference the container by the name you gave in your docker-compose.yml file.
In this case you should use
DB_HOSTNAME: mysql

After searching and digging up through several googling attempt, the culprit of the problem soon appear. In this context, the database server is not in the same machine. In other words, the MySQL Database Server address is not localhost. So, how can the above MySQL database configuration by default is pointing to localhost address. Well, it seems that if there is no further definition of the host address, it will connect to the localhost address by default. Read the article for further reference about sequelize syntax pattern in this link.
So, in order to solve the problem, just modify the file with the right configuration database. The following is the correction of the configuration database :
const sequelize = require("sequelize")
const db = new sequelize("db_master","db_user","password", {
host : "10.0.2.2",
dialect: "mysql"
});
db.sync({});
module.exports = db;
Actually, the NodeJS application is running in a virtual server. It is a guest machine run in a VirtualBox application. On the other hand, MySQL Database server exist outside the guest machine. It is available in the host machine where the VirtualBox application is running. The host machine IP address is 10.0.2.2. So, in order to connect to MySQL Database Server in the host machine, the IP address of the host is 10.0.2.2.

use your connection string as :
mysql://username:password#mysql:(port_running_on_container)or(exposed_port)/db_name

Answers already exist, but to provide some further explanation:
You can't use 127.0.0.1 (localhost) to access other services/containers since each container will view that as inside itself. When running docker-compose, all your services will be entered into the same docker network. All services inside the same docker network, are able to reach eachother by service name.
hence, as already stated in previous answers: in your configuration, change db hostname from localhost to mysql.

three things to check before
make sure your service name must be MySQL
in Configure DB_HOST also a MySQL
And your backend service depends on mysql in docker-compose.yml
here is my success code
export const db = new Sequelize(
process.env.DB_NAME,
process.env.DB_USER,
process.env.DB_PASSWORD,
{
port: process.env.DB_PORT,
host:'mysql',
dialect: "mysql",
logging: false,
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
},
}
);

Related

Error when using docker-compose to generate a full-stack application

The API does not find the DB when using docker compose.
I already configured the DATABA_URL and it doesn't work.
.env file:
JWT_SECRET="palavrasecreta"
NODE_ENV=production
DATABASE_URL=postgres://postgres:1234#db:5432/postgres
docker-compose file:
version: "3"
services:
app-front-end:
build: charllenger-front/.
container_name: front-end-ui
expose:
- 3000
ports:
- 3000:3000
links:
- api
api:
container_name: charllenger-back-end-Api
build: Full-Stack-charlenger-API/.
volumes:
- ./src:/app/src
expose:
- 3001
ports:
- 3001:3001
depends_on:
- db
command: bash -c 'yarn migration:run && yarn dev'
links:
- db
db:
container_name: charllenger-Api-postgres
image: "postgres"
env_file:
- Full-Stack-charlenger-API/.env
expose:
- 5432
ports:
- 5432:5432
DATA SOURCE
import { DataSource } from "typeorm";
require("dotenv").config();
export const AppDataSource = new DataSource({
type: "postgres",
host: "database",
url: process.env.DATABASE_URL,
ssl:
process.env.NODE_ENV === "production"
? { rejectUnauthorized: false }
: false,
synchronize: false,
logging: true,
entities:
process.env.NODE_ENV === "production"
? ["src/entities/*.js"]
: ["src/entities/*.ts"],
migrations:
process.env.NODE_ENV === "production"
? ["src/migrations/*.js"]
: ["src/migrations/*.ts"],
});
AppDataSource.initialize()
.then(() => {
console.log("Data Source Initialized");
})
.catch((err) => {
console.error("Error during data source Initialization", err);
}
);
Migration
import { MigrationInterface, QueryRunner } from "typeorm";
export class initialMigration1673714934213 implements MigrationInterface {
name = 'initialMigration1673714934213'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "transaction" ("transaction_id" uuid NOT NULL, "value" numeric NOT NULL, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "debitedAccountAccountId" uuid, "creditedAccountAccountId" uuid, CONSTRAINT "PK_6e02e5a0a6a7400e1c944d1e946" PRIMARY KEY ("transaction_id"))`);
await queryRunner.query(`CREATE TABLE "user" ("user_id" uuid NOT NULL, "username" character varying NOT NULL, "password" character varying NOT NULL, "account" uuid, CONSTRAINT "REL_4ab2df0a57a74fdf904e0e2708" UNIQUE ("account"), CONSTRAINT "PK_758b8ce7c18b9d347461b30228d" PRIMARY KEY ("user_id"))`);
await queryRunner.query(`CREATE TABLE "account" ("account_id" uuid NOT NULL, "balance" double precision NOT NULL, CONSTRAINT "PK_ea08b54a9d7322975ffc57fc612" PRIMARY KEY ("account_id"))`);
await queryRunner.query(`ALTER TABLE "transaction" ADD CONSTRAINT "FK_bbbfcdb3330cc4e5846f2d23200" FOREIGN KEY ("debitedAccountAccountId") REFERENCES "account"("account_id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "transaction" ADD CONSTRAINT "FK_4ece0117a7c2689832bab37209b" FOREIGN KEY ("creditedAccountAccountId") REFERENCES "account"("account_id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "user" ADD CONSTRAINT "FK_4ab2df0a57a74fdf904e0e27086" FOREIGN KEY ("account") REFERENCES "account"("account_id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "user" DROP CONSTRAINT "FK_4ab2df0a57a74fdf904e0e27086"`);
await queryRunner.query(`ALTER TABLE "transaction" DROP CONSTRAINT "FK_4ece0117a7c2689832bab37209b"`);
await queryRunner.query(`ALTER TABLE "transaction" DROP CONSTRAINT "FK_bbbfcdb3330cc4e5846f2d23200"`);
await queryRunner.query(`DROP TABLE "account"`);
await queryRunner.query(`DROP TABLE "user"`);
await queryRunner.query(`DROP TABLE "transaction"`);
}
}
Error:
enter image description here
t's working on another computer, I've already changed localhost to db, I've tried other ports and it doesn't work.
In the docker-compose you define your database container as db.
db:
container_name: charllenger-Api-postgres
image: "postgres"
db: is the servicename.
If you want to connect from your api to the database container, inside your docker network, you need to use this servicename as db_host.
the section:
ports:
- 5432:5432
means: map the port 5432 inside the container to my host (your Pc where you installed docker).
So you can access the container on his port 5432, from your PC with localhost:5432 and this works fine if you execute your code localy even if postgres is running inside a container.
If your code runs in a container localhost refers to that container.
Lets say each container has it own localhost. So you can access the other containers only by its servicename. There are a few other possibilities, but lets remain to use the servicename.
In side your Typeorm configuration ensure that the connection to the database use the servicename when you run the code inside the conatiner, or localhost if you run it directly on your pc without docker.
When you deploy it to Production, again you must look where the db_host is. That depends on your deployment. If you use an external DB from a provvider it should be a full qualified domain name. If you deploy your db by yourself it depends if you use docker Kubernetes or what else.

Unable to connect nodejs app to mongodb using docker-compose

Simple Node app and mongo containers created using docker-compose below... What am I missing?
mongodb://user:password#mongo:27017/
version: '3.8'
services:
mongo:
image: mongo
restart: always
environment:
- MONGO_INITDB_ROOT_USERNAME=user
- MONGO_INITDB_ROOT_PASSWORD=password
app:
image: app
build:
context: ./app
dockerfile: Dockerfile
ports:
- "3000:3000"
depends_on:
- mongo
I've read several posts on the same issue and the official mongo docker page and seem to be doing everything correct. Keep getting the following msg.
app_1 | mongodb://user:password#mongo:27017/ {
app_1 | autoIndex: false,
app_1 | poolSize: 10,
app_1 | bufferMaxEntries: 0,
app_1 | useNewUrlParser: true,
app_1 | useUnifiedTopology: true
app_1 | }
app_1 | MongoDB connection with retry
app_1 | MongoDB connection unsuccessful, retry after 5 seconds. 2
I prepared interesting test for you
version: '3.8'
services:
mongo:
image: mongo
environment:
- MONGO_INITDB_ROOT_USERNAME=user
- MONGO_INITDB_ROOT_PASSWORD=password
healthcheck:
test: "echo 'db.runCommand(\"ping\").ok'"
interval: 5s
timeout: 5s
retries: 3
app:
image: mongo
command: "mongosh mongodb://user:password#mongo:27017/admin --eval \"printjson(db.test.insertOne({'a': 1}))\""
ports:
- "3000:3000"
depends_on:
- mongo
It will print
app_1 | {
app_1 | acknowledged: true,
app_1 | insertedId: ObjectId("63696c4e99703eb4ab9fba62")
app_1 | }
but if you will change
command: "mongosh mongodb://user:password#mongo:27017/admin --eval \"printjson(db.test.insertOne({'a': 1}))\""
to
command: "mongosh mongodb://user:password#mongo:27017/local --eval \"printjson(db.test.insertOne({'a': 1}))\""
you will see error. Even if you will add MONGO_INITDB_DATABASE to mongo with value local.
You can test it running in second console command:
docker-compose run app bash
and then try
mongosh mongodb://user:password#mongo:27017/admin --eval "printjson(db.test.insertOne({'a': 1}))"
with success
and
mongosh mongodb://user:password#mongo:27017/local --eval "printjson(db.test.insertOne({'a': 1}))"
that failing. You can see logs from mongo like
mongo_1 | {"t":{"$date":"2022-11-07T20:40:35.686+00:00"},"s":"I", "c":"ACCESS", "id":20249, "ctx":"conn6","msg":"Authentication failed","attr":{"mechanism":"SCRAM-SHA-256","speculative":true,"principalName":"user","authenticationDatabase":"local","remote":"172.20.0.3:50382","extraInfo":{},"error":"UserNotFound: Could not find user \"user\" for db \"local\""}}
mongo_1 | {"t":{"$date":"2022-11-07T20:40:35.687+00:00"},"s":"I", "c":"ACCESS", "id":20249, "ctx":"conn6","msg":"Authentication failed","attr":{"mechanism":"SCRAM-SHA-1","speculative":false,"principalName":"user","authenticationDatabase":"local","remote":"172.20.0.3:50382","extraInfo":{},"error":"UserNotFound: Could not find user \"user\" for db \"local\""}}
mongo_1 | {"t":{"$date":"2022-11-07T20:40:35.688+00:00"},"s":"I", "c":"NETWORK", "id":22944, "ctx":"conn5","msg":"Connection ended","attr":{"remote":"172.20.0.3:50374","uuid":"b77fff1f-b832-4900-9c2d-1e7fd1e79424","connectionId":5,"connectionCount":1}}
mongo_1 | {"t":{"$date":"2022-11-07T20:40:35.699+00:00"},"s":"I", "c":"NETWORK", "id":22944, "ctx":"conn6","msg":"Connection ended","attr":{"remote":"172.20.0.3:50382","uuid":"3995bcbf-706d-4bed-92a2-04736305b7c2","connectionId":6,"connectionCount":0}}
this problem is described in topic User not found on MongoDB Docker image with authentication
You can authenticate with user,password against admin db, not mydb
You can read more about creating database with user and password here:
How to create a DB for MongoDB container on start up?

Docker swarm secret not working correctly in node.js api (mongoDB)

I am trying to get my mongo_username and mongo_password in a swarm secret, but for some reason they are converted? I get this error in the container log
/usr/src/app/node_modules/saslprep/index.js:99
throw new Error(
^
Error: Prohibited character, see https://tools.ietf.org/html/rfc4013#section-2.3
at saslprep (/usr/src/app/node_modules/saslprep/index.js:99:11)
at continueScramConversation (/usr/src/app/node_modules/mongodb/lib/core/auth/scram.js:126:36)
at /usr/src/app/node_modules/mongodb/lib/core/auth/scram.js:111:5
at MessageStream.messageHandler (/usr/src/app/node_modules/mongodb/lib/cmap/connection.js:277:5)
at MessageStream.emit (events.js:315:20)
at processIncomingData (/usr/src/app/node_modules/mongodb/lib/cmap/message_stream.js:144:12)
at MessageStream._write (/usr/src/app/node_modules/mongodb/lib/cmap/message_stream.js:42:5)
at writeOrBuffer (_stream_writable.js:353:12)
at MessageStream.Writable.write (_stream_writable.js:303:12)
at Socket.ondata (_stream_readable.js:713:22)
at Socket.emit (events.js:315:20)
at addChunk (_stream_readable.js:302:12)
at readableAddChunk (_stream_readable.js:278:9)
at Socket.Readable.push (_stream_readable.js:217:10)
at TCP.onStreamRead (internal/stream_base_commons.js:186:23)
I added the secret like this
echo admin | docker secret create mongo_username -
echo totallySecurePassword23456789 | docker secret create mongo_password -
and when i log those two secrets in my DB connect function like this:
const mongoose = require("mongoose"); // For connection to DB
const {
MONGO_USERNAME,
MONGO_PASSWORD,
MONGO_HOSTNAME,
MONGO_PORT,
MONGO_DATABASE_NAME,
} = process.env;
console.log(MONGO_USERNAME);
console.log(MONGO_PASSWORD);
console.log(MONGO_HOSTNAME);
console.log(MONGO_PORT);
console.log(MONGO_DATABASE_NAME);
const url = `mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}#${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DATABASE_NAME}?retryWrites=true$w=majority`;
console.log(url);
const connectDB = async () => {
const conn = await mongoose.connect(url, {
useNewUrlParser: true,
useCreateIndex: true,
useFindAndModify: false,
useUnifiedTopology: true,
});
console.log(`MongoDB Connected: ${conn.connection.host}`.cyan.underline.bold);
};
module.exports = connectDB;
They show up correctly as:
admin
totallySecurePassword23456789
host.docker.internal
27020
mainDB
and yet the url which is made which is supposed to look like mongodb://admin:totallySecurePassword23456789#host.docker.internal:27020/mainDB?retryWrites=true$w=majority
shows up as #host.docker.internal:27020/mainDB?retryWrites=true$w=majority
And this ofcourse makes the connection fail
the hostname, port and database_name work fine because these are defined as normal environment variables
Any help would be really appreciated, and if more info is needed please let me know!
Edit 1:
Here is the docker-compose file i use to run docker stack:
version: "3.8"
services:
main:
image: main:5.0.0
environment:
- MONGO_USERNAME_FILE=/run/secrets/mongo_username
- MONGO_PASSWORD_FILE=/run/secrets/mongo_password
- MONGO_HOSTNAME=host.docker.internal
- MONGO_PORT=27020
- MONGO_DATABASE_NAME=mainDB
secrets:
- mongo_username
- mongo_password
networks:
- main-net
ports:
- "80:3001"
deploy:
replicas: 1
restart_policy:
condition: on-failure
delay: 10s
window: 60s
networks:
main-net:
driver: overlay
secrets:
mongo_username:
external: true
mongo_password:
external: true
Edit 2:
Fixed the compose file missing the _FILE behind the username and password
After lots of investigating i found out i was having this problem https://github.com/aspnet/Configuration/issues/701, with no good fix found i settled on editing the entrypoint i was using (https://github.com/BretFisher/node-docker-good-defaults/blob/main/docker-entrypoint.sh) so it removed the end of line stuff before setting it as a environment variable by using
export "$var"="${val//[$'\t\r\n ']}"
I assume you use gnu bash. If you use echo shell builtin without -n option, it automatically adds new line to provided string.
Try these:
echo -n admin | docker secret create mongo_username -
echo -n totallySecurePassword23456789 | docker secret create mongo_password -
If you want to check your secret value whether includes new line, execute the following command on the machine where your docker cli resides:
docker container exec <your_container_name or id> cat -e /run/secrets/<your_secret_name>
If this command returns your value followed by $ symbol then we can conclude that new line character was appended while you were creating secret.
Note: I presume your container is a linux container. Also, be sure your container is in running state and its PATH environment variable must include the directory path where cat binary reside.

(Docker-Compose) UnhandledPromiseRejectionWarning when connecting node and postgres

I am trying to connect the containers for postgres and node. Here is my setup:
yml file:
version: "3"
services:
postgresDB:
image: postgres:alpine
container_name: postgresDB
ports:
- "5432:5432"
environment:
- POSTGRES_DB=myDB
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=Thisisngo1995!
express-server:
build: ./
environment:
- DB_SERVER=postgresDB
links:
- postgresDB
ports:
- "3000:3000"
Dockerfile:
FROM node:12
WORKDIR /usr/src/app
COPY package.json ./
RUN npm install
COPY . .
COPY ormconfig.docker.json ./ormconfig.json
EXPOSE 3000
CMD ["npm", "start"]
connect to postgres:
let { Pool, Client } = require("pg");
let postgres = new Pool({
host: "postgresDB",
port: 5432,
user: "postgres",
password: "Thisisngo1995!",
database: "myDB",
});
module.exports = postgres;
and here is how I handled my endpoint:
exports.postgres_get_controller = (req, resp) => {
console.log("Reached Here");
postgres
.query('SELECT * FROM public."People"')
.then((results) => {
console.log(results);
resp.send({ allData: results.rows });
})
.catch((e) => console.log(e));
};
Whenever I try to touch the endpoint above, I get this error in the container:
Reasons why?
Note: I am able to have everything functioning on my local machine (without docker) simply by changing "host: localhost"
Your postgres database name and username should be the same
You can use docker-compose-wait to make sure interdependent services are launched in proper order.
See below on how to use it for your case.
update the final part of your Dockerfile as below;
# ...
# this will be used to check if DB is up
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.7.3/wait ./wait
RUN chmod +x ./wait
CMD ./wait && npm start
Update some parts of your docker-compose.yml as below:
express-server:
build: ./
environment:
- DB_SERVER=postgresDB
- WAIT_HOSTS=postgresDB:5432
- WAIT_BEFORE_HOSTS=4
links:
- postgresDB
depends_on:
- postgresDB
ports:
- "3000:3000"

Not able to connect to Elasticsearch from docker container (node.js client)

I have set up an elasticsearch/kibana docker configuration and I want to connect to elasticsearch from inside of a docker container using the #elastic/elasticsearch client for node. However, the connection is "timing out".
The project is taken with inspiration from Patrick Triest : https://blog.patricktriest.com/text-search-docker-elasticsearch/
However, I have made some modification in order to connect kibana, use a newer ES image and the new elasticsearch node client.
I am using the following docker-compose file:
version: "3"
services:
api:
container_name: mp-backend
build: .
ports:
- "3000:3000"
- "9229:9229"
environment:
- NODE_ENV=local
- ES_HOST=elasticsearch
- PORT=3000
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.5.1
container_name: elasticsearch
environment:
- node.name=elasticsearch
- cluster.name=es-docker-cluster
- discovery.type=single-node
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- "http.cors.allow-origin=*"
- "http.cors.enabled=true"
- "http.cors.allow-headers=X-Requested-With,X-Auth-Token,Content-Type,Content-Length,Authorization"
- "http.cors.allow-credentials=true"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- data01:/usr/share/elasticsearch/data
ports:
- 9200:9200
networks:
- elastic
kibana:
image: docker.elastic.co/kibana/kibana:7.5.1
ports:
- "5601:5601"
links:
- elasticsearch
networks:
- elastic
depends_on:
- elasticsearch
volumes:
data01:
driver: local
networks:
elastic:
driver: bridge
When building/ bringing the container up, I able to get a response from ES: curl -XGET "localhost:9200", "you know, for search"... And kibana is running and able to connect to the index.
I have the following file located in the backend container (connection.js):
const { Client } = require("#elastic/elasticsearch");
const client = new Client({ node: "http://localhost:9200" });
/*Check the elasticsearch connection */
async function health() {
let connected = false;
while (!connected) {
console.log("Connecting to Elasticsearch");
try {
const health = await client.cluster.health({});
connected = true;
console.log(health.body);
return health;
} catch (err) {
console.log("ES Connection Failed", err);
}
}
}
health();
If I run it outside of the container then I get the expected response:
node server/connection.js
Connecting to Elasticsearch
{
cluster_name: 'es-docker-cluster',
status: 'yellow',
timed_out: false,
number_of_nodes: 1,
number_of_data_nodes: 1,
active_primary_shards: 7,
active_shards: 7,
relocating_shards: 0,
initializing_shards: 0,
unassigned_shards: 3,
delayed_unassigned_shards: 0,
number_of_pending_tasks: 0,
number_of_in_flight_fetch: 0,
task_max_waiting_in_queue_millis: 0,
active_shards_percent_as_number: 70
}
However, if I run it inside of the container:
docker exec mp-backend "node" "server/connection.js"
Then I get the following response:
Connecting to Elasticsearch
ES Connection Failed ConnectionError: connect ECONNREFUSED 127.0.0.1:9200
at onResponse (/usr/src/app/node_modules/#elastic/elasticsearch/lib/Transport.js:214:13)
at ClientRequest.<anonymous> (/usr/src/app/node_modules/#elastic/elasticsearch/lib/Connection.js:98:9)
at ClientRequest.emit (events.js:223:5)
at Socket.socketErrorListener (_http_client.js:415:9)
at Socket.emit (events.js:223:5)
at emitErrorNT (internal/streams/destroy.js:92:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
at processTicksAndRejections (internal/process/task_queues.js:81:21) {
name: 'ConnectionError',
meta: {
body: null,
statusCode: null,
headers: null,
warnings: null,
meta: {
context: null,
request: [Object],
name: 'elasticsearch-js',
connection: [Object],
attempts: 3,
aborted: false
}
}
}
So, I tried changing the client connection to (I read somewhere that this might help):
const client = new Client({ node: "http://172.24.0.1:9200" });
Then I am just "stuck" waiting for a response. Only one console.log of "Connecting to Elasticsearch"
I am using the following version:
"#elastic/elasticsearch": "7.5.1"
As you probably see, I do not have a full grasp of what is happening here... I have also tried to add:
links:
- elasticsearch
networks:
- elastic
To the api service, without any luck.
Does anyone know what I am doing wrong here? Thank you in advance :)
EDIT:
I did a "docker network inspect" on the network with *_elastic. There I see the following:
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.22.0.0/16",
"Gateway": "172.22.0.1"
}
]
},
Changing the client to connect to the "GateWay" Ip:
const client = new Client({ node: "http://172.22.0.1:9200" });
Then it works! I am still wondering why as this was just "trial and error" Is there any way to obtain this Ip without having to inspect the network?
In Docker, localhost (or the corresponding IPv4 address 127.0.0.1, or the corresponding IPv6 address ::1) generally means "this container"; you can't use that host name to access services running in another container.
In a Compose-based setup, the names of the services: blocks (api, elasticsearch, kibana) are usable as host names. The caveat is that all of the services have to be on the same Docker-internal network. Compose creates one for you and attaches containers to it by default. (In your example api is on the default network but the other two containers are on a separate elastic network.) Networking in Compose in the Docker documentation has some more details.
So to make this work, you need to tell your client code to honor the environment variable you're setting that points at Elasticsearch
const esHost = process.env.ES_HOST || 'localhost';
const esUrl = 'http://' + esHost + ':9200';
const client = new Client({ node: esUrl });
In your docker-compose.yml file delete all of the networks: blocks to use the provided default network. (While you're there, links: is unnecessary and Compose provides reasonable container_name: for you; api can reasonably depends_on: [elasticsearch].)
Since we've provided a fallback for $ES_HOST, if you're working in a host development environment, it will default to using localhost; outside of Docker where it means "the current host" it will reach the published port of the Elasticsearch container.

Resources