You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker环境下Express/NodeJS无法连接Redis但MySQL正常的问题

问题

核心问题:NodeJS本地运行时可正常连接MySQL和Redis;Docker容器中运行时仅能连接MySQL,无法连接Redis。

Docker Compose配置

version: '3'
services:
    express-app:
        build:
            context: .
        ports:
            - 3000:3000
        depends_on:
            - redis-db
            - mysql-db
        environment:
            - MYSQL_HOST=mysql-db
            - REDIS_HOST=redis-db

    mysql-db:
        image: mysql:latest
        environment:
            MYSQL_DATABASE: twitter
            MYSQL_USER: user
            MYSQL_PASSWORD: user-password
            MYSQL_ROOT_PASSWORD: root-password
        ports:
            - '3306:3306'
        volumes:
            - my-twitter-db-mount:/var/lib/mysql

    redis-db:
        image: redis
        ports:
            - '6379:6379'
        volumes:
            - my-twitter-redis-mount:/var/lib/redis/data

volumes:
    my-twitter-db-mount:
    my-twitter-redis-mount:

NodeJS代码

const mysql = require('mysql2');
const redis = require('redis');

var connection;
var redisConnection;
const getConnection = (() => {
    console.log("################ "+process.env.MYSQL_HOST) ;
    console.log("################ "+process.env.REDIS_HOST) ;
    
    connection = mysql.createConnection({
        host: process.env.MYSQL_HOST || 'localhost',
        port: 3306,
        user: 'user',
        password: 'user-password'
    });
    
    redisConnection = redis.createClient({
        port: 6379,
        host: process.env.REDIS_HOST || 'localhost'
    });
    
    connection.connect();
    redisConnection.connect();
});

const queryFollowers = (async (ownerId) => {
    getConnection();
    let val = await redisConnection.get(`OwnerCache_${ownerId}`);
    if (val) {
        console.log("Returning the cached value "+val);
        return new Promise((resolve, reject)  => resolve(val));
    }
    console.log("No Cached value found for "+val+ " Querying database...");
    return new Promise((resolve, reject) => { 
        connection.query(`SELECT * from twitter.Users where id IN  (SELECT follower_id from twitter.User_Follower  WHERE user_id = ${ownerId})`, (err, rows, fields) => {
            if (err) reject(err);
            console.log("ROWS "+rows);
            let followers = [];
            if(rows.length > 0)  {
                rows.forEach(user => {
                    followers.push(user);
                });
                redisConnection.set(`OwnerCache_${ownerId}`, JSON.stringify(followers));
                redisConnection.expire(`OwnerCache_${ownerId}`, 10);
                resolve(followers);
            }
        });
    });
});

错误信息

使用桥接网络名称mysql-db可正常连接MySQL,但使用redis-db却无法连接Redis(本地运行时Node可连接两者,此时默认使用localhost)。

Listening on port 3000
Returning all the followers for ownerID 1
################ mysql-db
################ redis-db
node:internal/process/promises:288
            triggerUncaughtException(err, true /* fromPromise */);
            ^
Error: connect ECONNREFUSED 127.0.0.1:6379
    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1246:16)
Emitted 'error' event on Commander instance at:
    at RedisSocket.<anonymous> (/app/node_modules/@node-redis/client/dist/lib/client/index.js:339:14)
    at RedisSocket.emit (node:events:513:28)
    at RedisSocket._RedisSocket_connect (/app/node_modules/@node-redis/client/dist/lib/client/socket.js:117:14)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Commander.connect (/app/node_modules/@node-redis/client/dist/lib/client/index.js:162:9) {
  errno: -111,
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '127.0.0.1',
  port: 6379
}
Node.js v18.6.0

解决思路

  1. 修正Redis客户端参数格式
    你使用的是@node-redis/client(v4+版本),该版本不再支持将host和port作为顶级参数传入createClient,需要嵌套在socket对象中,或者使用URL格式:

    // 方式1:使用socket对象
    redisConnection = redis.createClient({
        socket: {
            host: process.env.REDIS_HOST || 'localhost',
            port: 6379
        }
    });
    
    // 方式2:使用URL格式
    redisConnection = redis.createClient({
        url: `redis://${process.env.REDIS_HOST || 'localhost'}:6379`
    });
    
  2. 确保Redis服务就绪后再连接
    depends_on仅保证容器启动顺序,不保证Redis服务完全就绪。可以在代码中添加重试逻辑:

    async function connectRedis() {
        try {
            await redisConnection.connect();
            console.log('Redis连接成功');
        } catch (err) {
            console.log('Redis连接失败,2秒后重试...');
            setTimeout(connectRedis, 2000);
        }
    }
    // 替换原redisConnection.connect()为connectRedis()
    
  3. 验证容器间网络连通性
    进入express-app容器,执行以下命令测试与Redis容器的网络连通性:

    docker exec -it <express-app容器ID> ping redis-db
    docker exec -it <express-app容器ID> telnet redis-db 6379
    

    如果telnet不通,查看Redis容器日志排查启动问题:

    docker logs redis-db
    
  4. 检查Redis挂载目录权限
    Redis容器默认使用redis用户运行,若挂载目录权限不正确会导致服务启动失败。可以在docker-compose.yml中显式指定用户:

    redis-db:
        image: redis
        ports:
            - '6379:6379'
        volumes:
            - my-twitter-redis-mount:/var/lib/redis/data
        command: redis-server --appendonly yes
        user: "redis"
    

内容的提问来源于stack exchange,提问作者Frederick Scott Smith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 22:24:32