Reputation: 1988
I have a Nest.js application running that connects to Redis cluster from the provided host/port like this:
const port = this.configService.get('REDIS_PORT')
const host = this.configService.get('REDIS_HOST').replace('rediss://', '')
this.logger.log(`Initializing Redis client at ${host}:${port}`)
const dev = true
const clusterConfig: ClusterOptions = {
scaleReads: 'all',
enableAutoPipelining: true,
redisOptions: {
password: this.configService.get('REDIS_PASSWORD'),
db: 0,
showFriendlyErrorStack: true,
tls: dev
? undefined
: {
checkServerIdentity: (_host, _cert) => {
// skip certificate hostname validation
return undefined
},
},
},
}
this.redis = new Cluster(
[
{ port: 6379, host: 'localhost' },
],
clusterConfig,
)
On stage environment, this works fine. If I run app inside Docker locally (where redis cluster is set up using docker compose), it works fine.
BUT, if I run redis cluster in Docker-compose and application on host machine, and try to connect to redis cluster using ports exposed to host machine from docker (localhost:6379), it cannot connect and writes the following logs:
ioredis:cluster:subscriber selected a subscriber 173.17.0.4:7002 +0ms
ioredis:redis status[173.17.0.4:7002 (ioredis-cluster(subscriber))]: wait -> wait +0ms
ioredis:cluster cluster slots result count: 3 +0ms
ioredis:cluster cluster slots result [0]: slots 5461~10922 served by [ '173.17.0.3:7001' ] +0ms
ioredis:cluster cluster slots result [1]: slots 0~5460 served by [ '173.17.0.2:7000' ] +0ms
ioredis:cluster cluster slots result [2]: slots 10923~16383 served by [ '173.17.0.4:7002' ] +0ms
ioredis:cluster:connectionPool Reset with [
ioredis:cluster:connectionPool { host: '173.17.0.3', port: 7001, readOnly: false },
ioredis:cluster:connectionPool { host: '173.17.0.2', port: 7000, readOnly: false },
ioredis:cluster:connectionPool { host: '173.17.0.4', port: 7002, readOnly: false }
ioredis:cluster:connectionPool ] +2ms
ioredis:cluster:connectionPool Disconnect ::1:7000 because the node does not hold any slot +0ms
ioredis:redis status[::1:7000]: wait -> close +2ms
ioredis:connection skip reconnecting since the connection is manually closed. +2ms
ioredis:redis status[::1:7000]: close -> end +0ms
ioredis:cluster:connectionPool Remove ::1:7000 from the pool +0ms
ioredis:cluster:connectionPool Connecting to 173.17.0.3:7001 as master +0ms
ioredis:redis status[173.17.0.3:7001]: wait -> wait +0ms
ioredis:cluster:connectionPool Connecting to 173.17.0.2:7000 as master +0ms
ioredis:redis status[173.17.0.2:7000]: wait -> wait +0ms
ioredis:cluster:connectionPool Connecting to 173.17.0.4:7002 as master +0ms
ioredis:redis status[173.17.0.4:7002]: wait -> wait +0ms
ioredis:cluster status: connecting -> connect +2ms
ioredis:redis status[173.17.0.2:7000]: wait -> connecting +0ms
ioredis:redis queue command[173.17.0.2:7000]: 0 -> cluster([ 'INFO' ]) +0ms
ioredis:cluster:subscriber subscriber has left, selecting a new one... +2ms
ioredis:redis status[::1:7000 (ioredis-cluster(subscriber))]: wait -> close +0ms
ioredis:connection skip reconnecting since the connection is manually closed. +0ms
ioredis:redis status[::1:7000 (ioredis-cluster(subscriber))]: close -> end +0ms
ioredis:cluster:subscriber selected a subscriber 173.17.0.2:7000 +0ms
ioredis:redis status[173.17.0.2:7000 (ioredis-cluster(subscriber))]: wait -> wait +0ms
ioredis:redis status[::1:7000 (ioredis-cluster(refresher))]: ready -> close +1ms
ioredis:connection skip reconnecting since the connection is manually closed. +1ms
ioredis:redis status[::1:7000 (ioredis-cluster(refresher))]: close -> end +0ms
ioredis:redis status[::1:7000 (ioredis-cluster(refresher))]: ready -> close +1ms
ioredis:connection skip reconnecting since the connection is manually closed. +1ms
ioredis:redis status[::1:7000 (ioredis-cluster(refresher))]: close -> end +0ms
ioredis:redis status[::1:7000 (ioredis-cluster(refresher))]: ready -> close +0ms
ioredis:connection skip reconnecting since the connection is manually closed. +0ms
ioredis:redis status[::1:7000 (ioredis-cluster(refresher))]: close -> end +0ms
I don't understand this part. It first says that
ioredis:cluster cluster slots result [0]: slots 5461~10922 served by [ '173.17.0.3:7001' ] +0ms
ioredis:cluster cluster slots result [1]: slots 0~5460 served by [ '173.17.0.2:7000' ] +0ms
ioredis:cluster cluster slots result [2]: slots 10923~16383 served by [ '173.17.0.4:7002' ] +1ms
and then:
Disconnect ::1:7000 because the node does not hold any slot +0ms
so does it hold any slot or not?
I can easily connect to this redis cluster from a RedisInsight client
I need app running on host machine for debugging. How do I fix this and why does this happen?
This is docker-compose config:
version: '2'
services:
api:
build:
context: .
dockerfile: Dockerfile
args:
NPM_TOKEN: ${NPM_TOKEN}
volumes:
- ./src:/usr/src/app/src
command: ['yarn', 'start:dev']
restart: always
ports:
- '3399:3399'
depends_on:
- redis-cluster
networks:
- inner_net
env_file:
- .env
env:
- REDIS_HOST=redis1
- REDIS_PORT=7000
redis1:
image: redis:3
ports:
- "6379:7000"
volumes:
- ./redis/redis-cluster1.tmpl:/usr/local/etc/redis/redis.conf
command: redis-server /usr/local/etc/redis/redis.conf
networks:
inner_net:
ipv4_address: 173.17.0.2
redis2:
image: redis:3
ports:
- "7001:7001"
volumes:
- ./redis/redis-cluster2.tmpl:/usr/local/etc/redis/redis.conf
command: redis-server /usr/local/etc/redis/redis.conf
networks:
inner_net:
ipv4_address: 173.17.0.3
redis3:
image: redis:3
ports:
- "7002:7002"
volumes:
- ./redis/redis-cluster3.tmpl:/usr/local/etc/redis/redis.conf
command: redis-server /usr/local/etc/redis/redis.conf
networks:
inner_net:
ipv4_address: 173.17.0.4
redis-cluster:
tty: true
build:
context: redis
args:
redis_version: '3.2.9'
hostname: server
depends_on:
- redis1
- redis2
- redis3
networks:
inner_net:
ipv4_address: 173.17.0.5
networks:
inner_net:
name: inner-service-net
driver: bridge
ipam:
driver: default
config:
- subnet: 173.17.0.0/16
Upvotes: 0
Views: 2075
Reputation: 1
have the same problem, and with the natMap it works by me
let natMap = {
"172.20.0.71:6381": {host: '127.0.0.1', port: 6381},
"172.20.0.72:6382": {host: '127.0.0.1', port: 6382},
"172.20.0.73:6383": {host: '127.0.0.1', port: 6383}
}
let theConnection = new redis.Cluster([
{ host: '127.0.0.1', port: 6381 },
{ host: '127.0.0.1', port: 6382 },
{ host: '127.0.0.1', port: 6383 }
// { host: 'localhost', port: 6381 },
// { host: 'localhost', port: 6382 },
// { host: 'localhost', port: 6383 }
], {
redisOptions: {
username: 'default',
password: 'yourPassword',
tls: undefined
},
natMap:natMap,
dnsLookup: (address, callback) => callback(null, address),
scaleReads: 'slave',
enableAutoPipelining: true,
enableOfflineQueue: true,
enableReadyCheck: true,
slotsRefreshTimeout: 500000,
});
Upvotes: 0
Reputation: 1988
I have found an answer to this. For this to work, you have to provide ioredis with natMap
parameter. This is what worked for me:
const devNatMap = {
'173.17.0.2:7000': {
host: '127.0.0.1',
port: 7000,
},
'173.17.0.3:7001': {
host: '127.0.0.1',
port: 7001,
},
'173.17.0.4:7002': {
host: '127.0.0.1',
port: 7002,
},
}
const clusterConfig: ClusterOptions = {
scaleReads: 'all',
enableAutoPipelining: true,
natMap: dev ? devNatMap : undefined,
redisOptions: {
password: this.configService.get('REDIS_PASSWORD'),
db: 0,
showFriendlyErrorStack: true,
tls: dev
? undefined
: {
checkServerIdentity: (_host, _cert) => {
// skip certificate hostname validation
return undefined
},
},
},
}
this.redis = new Cluster([{ port, host }], clusterConfig)
Upvotes: 0