Search code examples
amazon-web-servicesdockerredisdocker-composeamazon-elasticache

Can't connect to elasticache redis from docker container running in EC2


As a part of my CI process, I am creating a docker-machine EC2 instance and running 2 docker containers inside of it via docker-compose. The server container test script attempts to connect to an AWS elasticache redis instance within the same VPC as the EC2. When the test script is run I get the following error:

1) Storage
       check cache connection
         should return seeded value in redis:
     Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/usr/src/app/test/scripts/test.js)
      at listOnTimeout (internal/timers.js:549:17)
      at processTimers (internal/timers.js:492:7)

Update: I can connect via redis-cli from the EC2 itself:

redis-cli -c -h ***.cache.amazonaws.com -p 6379 ping
> PONG

It looks like I cant connect to my redis instance because my docker container is using an IP that is not within the same VPC as my elasticache instance. How can I setup my docker config to use the same IP as the host machine while building my containers from remote images? Any help would be appreciated.

Relevant section of my docker-compose.yml:

version: '3.8'
services:
  server:
    build:
      context: ./
      dockerfile: Dockerfile
    image: docker.pkg.github.com/$GITHUB_REPOSITORY/$REPOSITORY_NAME-server:github_ci_$GITHUB_RUN_NUMBER
    container_name: $REPOSITORY_NAME-server
    command: npm run dev
    ports:
      - "8080:8080"
      - "6379:6379"
    env_file: ./.env

Server container Dockerfile:

FROM node:12-alpine

# create app dir
WORKDIR /usr/src/app

# install dependencies
COPY package*.json ./

RUN npm install

# bundle app source
COPY . .

EXPOSE 8080 6379

CMD ["npm", "run", "dev"]

Elasticache redis SG inbound rules: enter image description here

EC2 SG inbound rules: enter image description here


Solution

  • I solved the problem through extensive trial and error. The major hint that pointed me in the right direction was found in the Docker docs:

    By default, the container is assigned an IP address for every Docker network it connects to. The IP address is assigned from the pool assigned to the network...

    Elasticache instances are only accessible internally from their respective VPC. Based on my config, the docker container and the ec2 instance were running on 2 different IP addresses but only the EC2 IP was whitelisted to connect to Elasticache.

    I had to bind the docker container IP to the host EC2 IP in my docker.compose.yml by setting the container network_mode to "host":

    version: '3.8'
    services:
      server:
        image: docker.pkg.github.com/$GITHUB_REPOSITORY/$REPOSITORY_NAME-server:github_ci_$GITHUB_RUN_NUMBER
        container_name: $REPOSITORY_NAME-server
        command: npm run dev
        ports:
          - "8080:8080"
          - "6379:6379"
        network_mode: "host"
        env_file: ./.env
    ...