Docker service inter-communication: Setting up redis and a web app with Docker compose

Chad Smith
2 min readAug 22, 2023

As a full time FAANG engineer for the last several years, I am insulated from most industry trends. Right now in my spare time I’m working on a JavaScript web app and wanted to try out redis and Docker.

I started with an expressjs app and plugged in Redis. It was really straightforward: I installed redis on my ubuntu laptop (yarn add redis), and connected to it via my web app:

import { createClient } from "redis";

const redisClient = createClient();

All good. No surprises.

Next I decided to put everything in Docker, and to use docker-compose, which lets you easily declare Docker services that run in parallel. You can also have one service depend on another.

There are a couple gotchas here:

  1. Having one service depend on another with depends_on does not wait for the service to be “ready” before starting the one that depends on it; only that it was started.
  2. Due to network isolation, accessing the redis container’s network from your app’s container no longer works with the default redis connection of localhost:6379.

The fixes

Below is a working docker-compose.yml file that addresses the first point:


version: "3"
services:
my-redis-docker-service:
image: redis:latest
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
interval: 1s
timeout: 3s
retries: 5
command: ["redis-server"]

app:
depends_on:
my-redis-docker-service:
condition: service_healthy
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
volumes:
- .:/app
command: yarn dev
  • To fix the “ready” issue, a healthcheck is added to run redis-cli ping and confirm the output matches an actually running redis instance.
  • To fix the the networking issue and avoid this:
my-docker-app_1   | Server is running on http://localhost:3000
my-docker-app_1 | Error: connect ECONNREFUSED 127.0.0.1:6379
my-docker-app_1 | at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1595:16) {
my-docker-app_1 | errno: -111,
my-docker-app_1 | code: 'ECONNREFUSED',
my-docker-app_1 | syscall: 'connect',
my-docker-app_1 | address: '127.0.0.1',
my-docker-app_1 | port: 6379
my-docker-app_1 | }

you can use this:

import { createClient } from "redis";

export const redisClient = createClient({
url: "redis://redis-docker-service:6379", // works from Docker!
});

This is because of how networking works with docker-compose. The service name is used as a hostname in the container. In this case, the service name of my docker container is redis-docker-service , so I’m able to connect to it with the url redis://redis-docker-service:6379.

To have this work from within docker-compose or not, you can add

# Docker
ENV DOCKER_CONTAINER true

to your Docker file, then check if it’s set in your TypeScript code:

// webapp.ts

const redisClient = createClient(
process.env.DOCKER_CONTAINER === "true"
? {
url: "redis://redis-docker-service:6379",
}
: { url: "redis://localhost:6379" }
);

Conclusion

I’m new to Docker and docker-compose. While Chat GPT3 has been incredibly helpful to get me going faster than ever with these tools, it did not get this right, so I spent quite a bit of time wondering why I kept getting those ECONNREFUSED errors!

--

--