Search code examples
node.jsreactjsdockeramazon-ecsaws-fargate

How to configure port of React app fetch when deploying to ECS fargate cluster with two tasks


I have two docker images that communicate fine when deployed locally, but I'm not sure how to set up my app to correctly make fetch() calls from the React app to the correct port on the other app when they're both deployed as tasks on the same ECS cluster.

My react app uses a simple fetch('/fooService/' + barStr) type call, and my other app exposes a /fooService/{barStr} endpoint on port 8081.

For local deployment and local docker, I used setupProxy.js to specify a proxy:

const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = function(app) {
    app.use(createProxyMiddleware('/fooService',
        { target: 'http://fooImage:8081',
            changeOrigin: true
        }
        ));
}

In ECS this seems to do nothing, though. I see the setupProxy run when the image starts up, but the requests from my react app just go directly to {sameIPaddress}/fooService/{barStr}, ignoring the proxy specification entirely. I can see in the browser that the requests are being made over port 80. If these requests are made on port 8081 manually, they complete just fine, so the port is available and the service is running.

I've exposed port 8081 on the other task, and I can access it externally with no problem, I just am unclear on how to design my react app to point to it, since I won't necessarily know what IP address I will be assigned until the task launches. If I use a relative path, I cannot specify the port.

What's the idiomatic way to specify the destination of my fetch requests in this context?

Edit: If it is relevant, here is how the docker images are configured. They are built automatically on dockerhub and work fine if I deploy them in my local docker instance.

docker-compose.yaml

version: "3.8"
services:
  fooImage:
    image: myname/foo-image:0.1
    build: ./
    container_name: server
    ports:
      - '8081:8081'
  barImage:
    image: myname/bar-image:0.1
    build: ./bar
    container_name: front
    ports:
      - '80:80'
    stdin_open: true
    tty: true

Dockerfile - foo image

#
# Build stage
#
FROM maven:3.8.5-openjdk-18-slim AS build
COPY src /home/app/src
COPY pom.xml /home/app
RUN mvn -f /home/app/pom.xml clean package


FROM openjdk:18-alpine
COPY --from=build /home/app/target/*.jar /usr/local/lib/app.jar
EXPOSE 8081
ENTRYPOINT ["java", "-jar", "/usr/local/lib/app.jar"]

Dockerfile - bar image

FROM node:17-alpine

WORKDIR /app

COPY package.json ./
COPY package-lock.json ./

RUN npm install

COPY . .

CMD ["npm", "start"]

ECS Foo task ports Foo ports

ECS Bar task ports Bar ports


Solution

  • The solution to this issue was to return the proxy target to "localhost:8081". Per Amazon support:

    For quickest resolve your issue, you can try to change your proxy configuration from "http://server:8081" to "http://localhost:8081" and the proxy should work.

    That's because when using Fargate with awsvpc network mode, containers running in a Task share the same network namespace, which means containers can communicate with each other through localhost. (e.g. When back-end container listen at port 8081, front-end container can access back-end container via localhost:8081) And when using docker-compose [2], you can use hostname to communicate to another container that specified in the same docker-compose file. So proxying back-end traffic with "http://server:8081" in Fargate won't work and should be modified to "http://localhost:8081"."