So I'm writing a node application, and my docker-compose.yml looks like:
version: '2'
services:
redis:
image: "redis:latest"
web:
build: .
ports:
- "3000:3000"
volumes:
- .:/app
links:
- redis
emailworker:
build: .
env_file:
- ./.env
command: node ./lib/workers/email.js
volumes:
- .:/app
links:
- redis
smsworker:
build: .
env_file:
- ./.env
command: node ./lib/workers/sms.js
volumes:
- .:/app
links:
- redis
Pretty straight forward, a webserver, and two workers to process email and sms jobs. All has been great, until this afternoon, where nothing seemed to change, but I can not longer connect to the redis container when my app boots up. I run docker-compose up and I get the following error when trying to connect to redis using the kue node module:
Error: Redis connection to 127.0.0.1:6379 failed - connect ECONNREFUSED 127.0.0.1:6379
at Object.exports._errnoException (util.js:1022:11)
at exports._exceptionWithHostPort (util.js:1045:20)
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1087:14)
My kue connection to redis looks like:
const kue = require('kue'),
queue = kue.createQueue({
root: __dirname,
redis: {
host: 'redis',
port: 6379
}
});
queue.on('error', err => {
console.log('QUEUE ERROR: ', err);
});
Any ideas where I'm going wrong here? I just set this up last night and emails were happily being sent, and like I mentioned, the only thing that would have changed is app code in the web service. I'm developing on a Mac if that makes a difference and have the latest version of docker and docker-compose. A docker ps after doing a docker-compose up shows:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3af92333ad53 expapi_web "yarn docker" About a minute ago Up About a minute 0.0.0.0:3000->3000/tcp expapi_web_1
d26f1d81ad22 expapi_emailworker "node ./lib/workers/e" About a minute ago Up About a minute 3000/tcp expapi_emailworker_1
1695ec819777 expapi_smsworker "node ./lib/workers/s" About a minute ago Up About a minute 3000/tcp expapi_smsworker_1
5cb6701f3586 redis:latest "docker-entrypoint.sh" About a minute ago Up About a minute 6379/tcp expapi_redis_1
Related
I am trying to connect to redis from node js in docker, but I am facing an error. Redis container starts successfully and I can ping with redis-cli. I think the problem might be somewhere else. The below code and configuration works on ubuntu 20.04, but shows error on arch linux (Docker version 20.10.17):
Redis Client Error Error: connect EHOSTUNREACH 172.18.0.2:6379
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1237:16) {
errno: -113,
code: 'EHOSTUNREACH',
syscall: 'connect',
address: '172.18.0.2',
port: 6379
}
Here is my docker compose file:
version: "3.7"
services:
app:
image: node:18.4-alpine
command: sh -c "yarn run dev"
ports:
- "4000:4000"
working_dir: /app
volumes:
- ./:/app
env_file:
- ./.env
redis:
image: redislabs/rejson:latest
ports:
- "6379:6379"
Here, I am trying to connect to redis from nodejs (node-redis 4.1.1):
const socket = {
host: "redis",
port: 6379
}
export const redisClient = createClient({
socket,
database: 0,
legacyMode: true
})
redisClient.on("error", (err) => {
console.log("Redis Client Error", err)
});
This is probably a race condition. Can you add depends_on: redis to your app service? This will at least make sure that the redis service is Running before instantiating the application.
Also, it is good practice to add retry/wait loop in your application with a timeout for external connectivity for better resilience to such race condition problems. They are very common.
No matter what I try I can't seem to get my node app to connect to redis between containers within the same docker-compose yml config. I've seen a lot of similar questions but none of the answers seem to work.
I'm using official images in both cases, not building my own
I am putting "redis" as my host and setting it as hostname in my docker compose YML config
const client = redis.createClient({ host: "redis" });
in my redis.conf I am using bind 0.0.0.0
This what the console is printing out:
Redis connection to redis:6379 failed - getaddrinfo ENOTFOUND redis redis:6379
Error: connect ECONNREFUSED 127.0.0.1:6379
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1107:14)
errno: 'ECONNREFUSED',
code: 'ECONNREFUSED',
syscall: 'connect',
address: '127.0.0.1',
port: 6379
}
This is my docker-compose.yml
version: '3'
services:
server:
image: "node:10-alpine"
working_dir: /usr/src/app
user: "node"
command: "npm start"
volumes:
- .:/usr/src/app
ports:
- '3000:3000'
- '3001:3001'
- '9229:9229' # Node debugging port
environment:
- IS_DOCKER=1
- NODE_ENV=DEVELOPMENT
depends_on:
- db
db:
image: "redis:5.0-alpine"
expose:
- '6379'
volumes:
- ./redis.conf:/usr/local/etc/redis/redis.conf
- redis-data:/data
command:
- redis-server
- /usr/local/etc/redis/redis.conf
hostname: redis
volumes:
redis-data:
UPDATE
Here's my redis.conf, it's not much.
bind 0.0.0.0
appendonly yes
appendfilename "my_app.aof"
appendfsync always
UPDATE 2
Things I've noticed and tried
in my original setup, when I run docker inspect I can see they are both joined to the same network. when I exec.../bin/bash into the redis container I can successfully ping the server container but when I'm in the server container it can not ping the redis one.
network_mode: bridge -adding that to both containers does not work
I did get one baby step closer by trying out this:
server:
network_mode: host
redis:
network_mode: service:host
I'm on a Mac and in order to get host mode to work you need to do that. It does work in the sense that my server successfully connects to the redis container. However, hitting localhost:3000 does not work even though I'm forwarding the ports
version: '3'
services:
server:
image: "node:10-alpine"
#network_mode: bridge
#links is necessary if you use network_mode: bridge
#links: [redis]
networks:
- default
working_dir: /usr/src/app
user: "node"
command: "npm start"
volumes:
- .:/usr/src/app
ports:
- '3000:3000'
- '3001:3001'
- '9229:9229' # Node debugging port
environment:
- IS_DOCKER=1
- NODE_ENV=DEVELOPMENT
depends_on:
- redis
redis:
image: "redis:5.0-alpine"
#container_name: redis
#network_mode: bridge
networks:
- default
expose:
- '6379'
volumes:
- ./redis.conf:/usr/local/etc/redis/redis.conf
- redis-data:/data
command:
- redis-server
- /usr/local/etc/redis/redis.conf
volumes:
redis-data:
networks:
default:
Rename the container to the hostname you want to use: redis in your case instead of db. To make it accessible over the docker network you will have to put them on the same network like above or use network_mode: bridge and links: [redis] instead.
Try this to test your network:
docker ps to get the current container id or running name from the server container
docker exec -it id/name /bin/sh
Now you have a shell inside server and should be able to resolve redis via:
ping redis or nc -zv redis 6379
For those who still getting this error
i found that in new versions of redis - 4 and up
you need to configure the client like this:
const client = createClient({
socket: {
host: host,
port: process.env.REDIS_PORT,
},
});
it solved my problem
then in docker compose file you don't need to specify ports
version: "3.4"
services:
redis-server:
image: "redis:latest"
restart: always
api:
depends_on:
- redis-server
restart: always
build: .
ports:
- "5000:5000"
I have a running service within a container on my localhost machine
I Can't establish a connection with it even though I specified the port mapping within my docker-compose.yml here it is
version: '2.1'
services:
users-db:
container_name: users-db
build: ./services/users-service/src/db
ports:
- '27017:27017'
volumes:
- './services/users-service/src/db/:/data/db'
users-service:
container_name: users-service
build: './services/users-service/'
volumes:
- './services/users-service:/usr/src/app'
- './services/users-service/package.json:/usr/src/package.json'
ports:
- '3000:3000'
environment:
- NODE_ENV=test
- JWT_SECRET=fuckOffChinese
depends_on:
users-db:
condition: service_started
presence_db:
image: redis
presense_service:
container_name: presense_service
build: './services/presence-service/'
ports:
- "8081:8081"
environment:
- JWT_SECRET=thirdEyeSecret
- PORT=8081
volumes:
- './services/presence-service:/usr/src/app'
- './services/presence-service/package.json:/usr/src/package.json'
depends_on:
- presence_db
this is the command that I use to run this service
docker-compose run presense_service
and this is what I get every time I try to ping it from the terminal by simply doing an HTTP GET request
http: error: ConnectionError: HTTPConnectionPool(host='localhost', port=8081): Max retries exceeded with url: / (Caused by
NewConnectionError(': Failed to establish a new connection: [Errno
61] Connection refused',)) while doing GET request to URL:
http://localhost:8081/
I'm running macOS 10.13.5 and the server start noramally and here is the logs of it
> users-service#1.0.0 start /usr/src
> gulp --gulpfile app/gulpfile.js
[10:12:46] Working directory changed to /usr/src/app
[10:12:52] Using gulpfile /usr/src/app/gulpfile.js
[10:12:52] Starting 'start'...
[10:12:56] Finished 'start' after 3.99 s
[10:12:56] Starting 'lint'...
[10:12:57] Finished 'lint' after 239 ms
[10:12:57] Starting 'default'...
[10:12:57] Finished 'default' after 131 μs
[10:12:57] [nodemon] 1.18.2
[10:12:57] [nodemon] to restart at any time, enter `rs`
[10:12:57] [nodemon] watching: *.*
[10:12:57] [nodemon] starting `node ./index.js`
Server listening on: http://localhost:8081
Redis client connected
Try docker-compose run presense_service --service-ports, or better, use docker-compose up.
docker-compose run specifically doesn't apply the ports from your Compose file to "prevent port collisions with already-open ports" [1] - so you have to add this option, or specify them manually with the same options you would pass to docker run.
Ideally, use docker-compose up -d and then docker-compose logs -f presense_service to get logs. Shut your application down with docker-compose down.
If you really need to, you can comment services out of your docker-compose.yml file that you don't want started.
If you didn't know, the latest version of the compose format is 3.6 - 2.1 is over two years old (released with Docker v1.12.0 on 201607/28 [2]).
Proving this is easy - since I didn't have your code, I replaced all the image/build lines with image: nginx (and took the host path off any volumes).
Example modified compose file (just for reference):
version: '2.1'
services:
users-db:
container_name: users-db
image: nginx
ports:
- '27017:27017'
volumes:
- './services/users-service/src/db/:/data/db'
users-service:
container_name: users-service
image: nginx
volumes:
- '/usr/src/app'
- '/usr/src/package.json'
ports:
- '3000:3000'
environment:
- NODE_ENV=test
- JWT_SECRET=fuckOffChinese
depends_on:
users-db:
condition: service_started
presence_db:
image: redis
presense_service:
container_name: presense_service
image: nginx
ports:
- "8081:8081"
environment:
- JWT_SECRET=thirdEyeSecret
- PORT=8081
volumes:
- '/usr/src/app'
- '/usr/src/package.json'
depends_on:
- presence_db
Running docker ps after docker-compose up -d gives this (pay attention to the PORTS column):
my-machine$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f1b89cf3d6c2 nginx "nginx -g 'daemon of…" 19 seconds ago Up 14 seconds 80/tcp, 0.0.0.0:3000->3000/tcp users-service
be0e9b2bb005 nginx "nginx -g 'daemon of…" 19 seconds ago Up 13 seconds 80/tcp, 0.0.0.0:8081->8081/tcp presense_service
2efed2546926 nginx "nginx -g 'daemon of…" 20 seconds ago Up 14 seconds 80/tcp, 0.0.0.0:27017->27017/tcp users-db
c7a88a84f422 redis "docker-entrypoint.s…" 20 seconds ago Up 14 seconds 6379/tcp test_presence_db_1
...so there's nothing wrong with your port configuration. docker ps after docker-compose run presense_service, then, shows:
my-machine$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
89e4a4f90a75 nginx "nginx -g 'daemon of…" 28 seconds ago Up 21 seconds 80/tcp test_presense_service_run_1
2c91fcb5091d redis "docker-entrypoint.s…" 29 seconds ago Up 24 seconds 6379/tcp test_presence_db_1
...and therefore it was your command causing the problem. Happy to help as I've learnt something new :)
[1] https://docs.docker.com/compose/reference/run/
[2] https://docs.docker.com/release-notes/docker-engine/#1120-2016-07-28
Try this to find out if port 8081 is open/occupied:
netstat -l | grep 8081
When your server logs say
Server listening on: http://localhost:8081
The server will be inaccessible outside the Docker container. It looks like this is the default behavior of the Express JavaScript Web server, and many other frameworks when run in “developer” mode. You need to set the server to listen on all IP addresses, probably by passing 0.0.0.0 as the “bind” address. (Note that you cannot connect to 0.0.0.0, and saying “listen to 0.0.0.0” means “accept connections from anywhere”.
If your server is in fact based on Express, https://superuser.com/questions/582624/how-to-access-nodejs-server-on-lan might be informative to you.
I am trying to setup separate docker containers for rabbitmq and the consumer for the container, i.e., the process that would listen on the queue and perform the necessary tasks. I created the yml file, and the docker file.
I am able to run the yml file, however when I check the docker-compose logs I see where there are ECONNREFUSED errors.
NewUserNotification.js:
require('seneca')()
.use('seneca-amqp-transport')
.add('action:new_user_notification’, function(message, done) {
…
return done(null, {
pid: process.pid,
status: `Process ${process.pid} status: OK`
})
.listen({
type: 'amqp',
pin: ['action:new_user_notification’],
name: 'seneca.new_user_notification.queue',
url: process.env.AMQP_RECEIVE_URL,
timeout: 99999
});
error message in docker-compose log:
{"notice":"seneca: Action hook:listen,role:transport,type:amqp failed: connect ECONNREFUSED 127.0.0.1:5672.","code":
"act_execute","err":{"cause":{"errno":"ECONNREFUSED","code":"ECONNREFUSED","syscall":"connect","address":"127.0.0.1",
"port":5672},"isOperational":true,"errno":"ECONNREFUSED","code":"act_execute","syscall":"connect","address":"127.0.0.1",
"port":5672,"eraro":true,"orig":{"cause":{"errno":"ECONNREFUSED","code":"ECONNREFUSED","syscall":"connect","address":"127.0.0.1",
"port":5672},"isOperational":true,"errno":"ECONNREFUSED","code":"ECONNREFUSED","syscall":"connect","address":"127.0.0.1","port":5672},
"seneca":true,"package":"seneca","msg":"seneca: Action hook:listen,role:transport,type:amqp failed: connect ECONNREFUSED 127.0.0.1:5672.",
"details":{"message":"connect ECONNREFUSED 127.0.0.1:5672","pattern":"hook:listen,role:transport,type:amqp","instance":"Seneca/…………/…………/1/3.4.3/-“,
”orig$":{"cause":{"errno":"ECONNREFUSED","code":"ECONNREFUSED","syscall":"connect","address":"127.0.0.1","port":5672},"isOperational":true,
"errno":"ECONNREFUSED","code":"ECONNREFUSED","syscall":"connect","address":"127.0.0.1","port":5672}
sample docker-compose.yml file:
version: '2.1'
services:
rabbitmq:
container_name: "4340_rabbitmq"
tty: true
image: rabbitmq:management
ports:
- 15672:15672
- 15671:15671
- 5672:5672
volumes:
- /rabbitmq/lib:/var/lib/rabbitmq
- /rabbitmq/log:/var/log/rabbitmq
- /rabbitmq/conf:/etc/rabbitmq/
account:
container_name: "account"
build:
context: .
dockerfile: ./Account/Dockerfile
ports:
- 3000:3000
links:
- "mongo"
- "rabbitmq"
depends_on:
- "mongo"
- "rabbitmq"
new_user_notification:
container_name: "app_new_user_notification"
build:
context: .
dockerfile: ./Account/dev.newusernotification.Dockerfile
links:
- "mongo"
- "rabbitmq"
depends_on:
- "mongo"
- "rabbitmq"
command: ["./wait-for-it.sh", "rabbitmq:5672", "-t", "90", "--", "node", “newusernotification.js"]
amqp connection string:
(I tried both ways, with and without a user/pass)
amqp://username:password#rabbitmq:5672
I added the link attribute to the docker-compose file and referenced the name in the .env file(rabbitmq). I tried to run the NewUserNotification.js file from outside the container and it started fine. What could be causing this problem? Connection string issue? Docker-Compose.yml configuration issue? Other?
Seems the environment variable AMQP_RECEIVE_URL is not constructed properly. According to error log the listener is trying to connect to localhost(127.0.0.1) which is not the rabbitmq service container IP. Find the modified configurations for a working sample.
1 docker-compose.yml
version: '2.1'
services:
rabbitmq:
container_name: "4340_rabbitmq"
tty: true
image: rabbitmq:management
ports:
- 15672:15672
- 15671:15671
- 5672:5672
volumes:
- ./rabbitmq/lib:/var/lib/rabbitmq
new_user_notification:
container_name: "app_new_user_notification"
build:
context: .
dockerfile: Dockerfile
env_file:
- ./un.env
links:
- rabbitmq
depends_on:
- rabbitmq
command: ["./wait-for-it.sh", "rabbitmq:5672", "-t", "120", "--", "node", "newusernotification.js"]
2 un.env
AMQP_RECEIVE_URL=amqp://guest:guest#rabbitmq:5672
Note that I've passed the AMQP_RECEIVE_URL as an environment variable to new_user_notification service using env_file and got rid of the account service
3 Dockerfile
FROM node:7
WORKDIR /app
COPY newusernotification.js /app
COPY wait-for-it.sh /app
RUN npm install --save seneca
RUN npm install --save seneca-amqp-transport
4 newusernotification.js use the same file in the question.
5 wait-for-it.sh
It is possible that your RabbitMQ service is not fully up, at the time the connection is attempted from the consuming service.
If this is the case, in Docker Compose, you can wait for services to come up using a container called dadarek/wait-for-dependencies.
1). Add a new service waitforrabbit to your docker-compose.yml
waitforrabbit:
image: dadarek/wait-for-dependencies
depends_on:
- rabbitmq
command: rabbitmq:5672
2). Include this service in the depends_on section of the service that requires RabbitMQ to be up.
depends_on:
- waitforrabbit
3). Startup compose
docker-compose run --rm waitforrabbit
docker-compose up -d account new_user_notification
Starting compose in this manner will essentially wait for RabbitMQ to be fully up before the connection from the consuming service is made.
I'm running a React app on Node and Redis via docker compose:
version: "3"
services:
webapp:
build: ./
ports:
- "127.0.0.1:3000:9090"
depends_on:
- redis
command:
npm run start
nginx:
build: ./nginx
ports:
- "80:80"
environment:
- NGINX_HOST=127.0.0.1
- NGINX_PORT=80
command:
service nginx start
redis:
image: redis
ports:
- "6379:6379"
volumes:
- ./data:/data
Docker file:
FROM node:alpine
WORKDIR /usr/src/app
COPY package.json ./
RUN npm install
COPY . .
EXPOSE 9090
RUN npm run build_prod
Server.js:
const redisClient = RedisClient.createClient(6379,'redis');
I get a Redis connection refused error when I run docker-compose up --build:
redis_1 | 1:M 15 Nov 13:55:19.865 * Ready to accept connections
webapp_1 |
webapp_1 | > web.globalmap.fatmap.com#0.0.1 start /usr/src/app
webapp_1 | > node ./build/server.js
webapp_1 |
webapp_1 | events.js:193
webapp_1 | throw er; // Unhandled 'error' event
webapp_1 | ^
webapp_1 |
webapp_1 | Error: Redis connection to 127.0.0.1:6379 failed - connect ECONNREFUSED 127.0.0.1:6379
webapp_1 | at Object._errnoException (util.js:1031:13)
webapp_1 | at _exceptionWithHostPort (util.js:1052:20)
webapp_1 | at TCPConnectWrap.afterConnect [as oncomplete]
I would like to know how to get docker to link both containers correctly.
Looks like redis does not resolve to the correct IP address.
Try a redis URI when creating the client.
// [redis:]//[[user][:password#]][host][:port][/db-number][?db=db-number[&password=bar[&option=value]]]
const redisClient = RedisClient.createClient('redis://redis:6379');
Provide the username, password, and db number if appropriate.
This solved my issue with node not being able to connect to redis using docker-compose.yml
const redis_client = redis.createClient({host: 'redis'});
then inside of my docker-compose.yml file i have the following
version: '3'
services:
redis:
image: redis
socket:
container_name: socket
build:
context: .
dockerfile: Dockerfile
depends_on:
- redis
links:
- redis
source: https://github.com/docker-library/redis/issues/45
I haven't found any issues using process.env. to access the environment variable of docker.
I have declared the variable in the docker-compose.yml file.
version: '3.7'
services:
api:
build: .
container_name: api-framework
depends_on:
- redis
ports:
- 8080:6002
networks:
- fronted
- backend
environment:
redis_server_addr: redis
redis:
container_name: my-redis
image: "redis:5"
ports:
- 6379
networks:
- backend
Then, the configuration file has the following line.
redis_host: process.env.redis_server_addr
It works for me.