This is my first time of using docker and I am trying to 'dockerize' my nodejs
application which relies on redis data base as well as mongo atlas database.
I have created both containers for nodejs and redis but I can't seem to get them connected. When I start the redis container and start my nodejs application locally outside docker, it runs fine. My nodejs and my redis container are able to communicate. However, making the nodejs a container, I can't seem to connect to the redis database. I am using redis npm version ^4.0.2
and I am using windows 11.
Here are my codes so far:
my redis connection:
const redis = require('redis');
let redis_client = redis.createClient()
redis_client.connect()
redis_client.on('connect', function(){
console.log('redis client connected')
});
Dockerfile
FROM node:lts-alpine
WORKDIR /app
COPY package*.json ./
COPY client/package*.json client/
RUN npm run install-client --only=production
COPY api/package*.json api/
RUN npm run install-api --only=production
COPY client/ client/
RUN npm run client-build --prefix client
COPY api/ api/
USER node
CMD [ "npm", "start", "--prefix", "api" ]
EXPOSE 5000
docker-compose file
version: "3"
services:
redisDB:
container_name: redisDB
hostname: redis
image: redis
ports:
- "6379:6379"
fullstack-cms:
build: .
ports:
- "5000:5000"
env_file:
- ./api/.env
depends_on:
- redisDB
links:
- redisDB
I used this command to build the images: docker-compose up -d --build
However, I get error:
Error: connect ECONNREFUSED 127.0.0.1:6379
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1278:16) {
errno: -111,
code: 'ECONNREFUSED',
syscall: 'connect',
address: '127.0.0.1',
port: 6379}
How do I fix this error?
CodePudding user response:
There are several aspects of your compose configuration that aren't necessary, and a couple that may be causing problems:
As I mentioned in the comment,
links
is deprecated. When you create an environment usingdocker-compose
(or more generally, whenever you attach containers to a user-defined network), Docker maintains a DNS service that allows your containers to refer to each other by name.You don't need to set either the
container_name
orhostname
for your services in most cases.You may not need to publish ports for your redis container. If it's just acting as a backend for the
fullstack-cms
service then theports
section isn't necessary. That's only important if you intend to connect to redis from your host (or from a remote host).
Applying all those changes, we end up with something like this:
version: "3"
services:
redisdb:
image: redis
fullstack-cms:
build: .
env_file:
- ./app/.env
ports:
- "8000:8000"
(And you can drop the env_file
directive if you rename app/.env
to .env
, because docker-compose
will load that automatically.)
I'm not a competent Node.js developer, so I've written an example Python application that works correctly with the above configuration. You can find a complete, runnable example here if you're so inclined.
Looking at that code, you can see that there is logic around the initial database connection that will retry it until the connection is successful:
while True:
try:
db = redis.Redis(host="redisdb", port=6379, db=0)
db.set("color", "blue")
# A connection could fail because either (a) the hostname doesn't exist
# yet (that's the socket.gaierror exception) or (b) if the hostname
# resolves but we're unable to connecto redis (that's the
# redis.exceptions.ConnectionError exception).
except (redis.exceptions.ConnectionError, socket.gaierror):
print('waiting for redis', file=sys.stderr)
time.sleep(1)
else:
break
You may want to implement something similar in your node.js code. You can test if it's a timing problem by bringing up the services separately. First bring up redis:
docker-compose up -d redisdb
Wait a minute, then bring up the frontend:
docker-compose up fullstack-cms
If this works, but a simple docker-compose up
fails, it's probably a timing issue.
CodePudding user response:
I solved the problem with this code:
let redis_client = redis.createClient({
url: 'redis://redis:6379',
legacyMode: true,
})
Thanks for the first comment for a headup.