Exposing a React app in a Docker container - node.js

I'm attempting to expose a react application to the Docker container it currently sits inside.
My Dockerfile successfully builds my image and runs my application on the configured port (8080). I then try to bind port 8080 of the container to port 8080 of the host. However, when I visit the host machine at port 8080 my application is not here.
docker run -d -p 8080:8080 --name react-deployment-container react-deployment:dev
I have an existing node application already exposed on the same host machine running on a different port (3000), so I am confident it is not an issue binding a port when running the Docker container.
I think the issue might be the way I am attempting to expose the application in my Webpack configuration. Webpack builds perfectly but doesn't appear to available to the Docker container.
webpack.config.js
devServer: {
contentBase: path.join(__dirname, "dist"),
compress: true,
host: '0.0.0.0',
port: 8080
}
package.json
"scripts": {
"start": "webpack-dev-server --host 0.0.0.0"
},
I have tinkered with the configuration recommended in the two questions below with no luck.
How to make the webpack dev server run on port 80 and on 0.0.0.0 to make it publicly accessible?
https://github.com/webpack/webpack-dev-server/issues/547
The repo for this project is here

Related

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
ECS Bar task ports
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"."

Aws EC2 port 80 connection refused

I am trying to run a node js server on aws EC2
My dockerfile:
FROM node:lts-alpine
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 80
CMD ["node", "server.js"]
Inside my server.js is an express web server listening for port 80.
I included port 80 into my inbound rules:
But still when I try to open a public DNS or an associated domain I get this:
Any ideas what I am doing wrong?
It seems that your container's port 80 is not assigned to the host's port. EXPOSE instruction does not do this for you. From the Docker docs:
The EXPOSE instruction does not actually publish the port. It functions as a type of documentation between the person who builds the image and the person who runs the container, about which ports are intended to be published. To actually publish the port when running the container, use the -p flag on docker run to publish and map one or more ports, or the -P flag to publish all exposed ports and map them to high-order ports.

On what PORT is my docker container with a React app running? Reacts' default PORT or EXPOSE from Dockerfile?

I'm a newbie to Docker so please correct me if anything I'm stating is wrong.
I created a React app and wrote a following Dockerfile in the root repository:
# pull official base image
FROM node:latest
# A directory within the virtualized Docker environment
# Becomes more relevant when using Docker Compose later
WORKDIR /usr/src/app
# Copies package.json and package-lock.json to Docker environment
COPY package*.json ./
# Installs all node packages
RUN npm install
# Copies everything over to Docker environment
COPY . .
# Uses port which is used by the actual application
EXPOSE 8080
# Finally runs the application
CMD [ "npm", "start" ]
My goal is to run the docker image in a way, that I can open the React app in my browser (with localhost).
Since in the Dockerfile I'm Exposing the app to the PORT: 8080. I thought I can run:
docker run -p 8080:8080 -t <name of the docker image>
But apparently the application is accessible through 3000 in the container, cause when I run:
docker run -p 8080:3000 -t <name of the docker image>
I can access it with localhost:8080.
What's the point of the EXPOSE port in the Dockerfile, when the service running in its container is accessible through a different port?
When containerizing a NodeJS app, do I always have to make sure that process.env.PORT in my app is the same as the EXPOSE in the Dockerfile?
EXPOSE is for telling docker what ports from inside the application can be exposed. It doesn't mean anything if you do not use those port inside (container -> host).
The EXPOSE is very handy when using docker run -P -t <name of the docker image> (-P capital P) to let Docker automatically publish all the exposed ports to random ports on the host (try it out. then run docker ps or docker inspect <containerId> and checking the output).
So if your web Server (React app) is running on port 3000 (inside the container) you should EXPOSE 3000 (instead of 8080) to properly integrate with the Docker API.
It's kind of weird.
Its just documentation in a sense.
https://docs.docker.com/engine/reference/builder/#:~:text=The%20EXPOSE%20instruction%20informs%20Docker,not%20actually%20publish%20the%20port.
The EXPOSE instruction does not actually publish the port. It
functions as a type of documentation between the person who builds the
image and the person who runs the container, about which ports are
intended to be published. To actually publish the port when running
the container, use the -p flag on docker run to publish and map one or
more ports, or the -P flag to publish all exposed ports and map them
to high-order ports.
do I always have to make sure that process.env.PORT in my app is the
same as the EXPOSE in the Dockerfile?
Yes. You should.
And then you also need to make sure that port actually gets published, when you use the docker run command or in your docker-compose.yml file, or however you plan on running docker.
Actually react app runs the default port 3000. so you must to mention ports and expose in docker-compose.yml. Now I'm changing the 3000 port to 8081
frontend:
container_name: frontend
build:
context: ./frontend/app
dockerfile: ../Dockerfile
volumes:
- ./frontend/app:/home/devops/frontend/app
- /home/devops/frontend/app/node_modules
ports:
- "8081:3000"
expose:
- 8081
command: ["npm", "start"]
restart: always
stdin_open: true
And run the docker
$ sudo docker-compose up -d
Then check the running containers for find the running port
$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
83b970baf16d devops_frontend "docker-entrypoint..." 31 seconds ago Up 30 seconds 8081/tcp, 0.0.0.0:8081->3000/tcp frontend
It's resolved. check your public port
$ curl 'http://0.0.0.0:8081'

Containerized NodeJS application on podman not reachable

I'm running a nodejs app in a pod (together with a mongo container)
Nodejs app listens on port 3000, which I expose from the container.
I have published port 3000 on the pod.
The container starts successfully (logs verified), but I can't reach my application on the host. When I curl to my app from within the pod it works.
Containers run rootfull, OS: CentOS Linux release 8.0.1905 (Core).
What am I missing?
curl http://localhost:3000
curl: (7) Failed to connect to localhost port 3000: No route to host
podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
30da37306acf registry.gitlab.com/xxx/switchboard:master node main.js 34 minutes ago Up 34 minutes ago 0.0.0.0:3000->3000/tcp switchboard-app
acc08c71147b docker.io/library/mongo:latest mongod 35 minutes ago Up 35 minutes ago 0.0.0.0:3000->3000/tcp switchboard-mongo
podman port switchboard-app
3000/tcp -> 0.0.0.0:3000
app.listen(3000, "0.0.0.0",function () {
console.log('App is listening on port 3000!');
});
FROM node:13
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY /dist/apps/switchboard .
EXPOSE 3000
CMD [ "node", "main.js" ]
If you want to create production docker build, you can go another way. It's not a good idea to do npm install inside container, because it will be too large. Run npm run build first, and then copy builded statics into docker container, created with nginx image.
So your Dockerfile shoud look like:
FROM nginx:1.13.0-alpine
COPY build/* /usr/share/nginx/html/
also specify exposed ports correctly with docker run. So, if you want expose 3000, your steps is:
cd /project/dir
docker build -t switchboard-app .
docker run -d -p 3000:80 --name switchboard-app switchboard-app

How do you expose port 3000 using an Azure Web App Container?

I'm running a react boilerplate app within a docker container, hosted Azure Web App Containers.
Locally, I spin the app up with:
docker run -p 3000:3000 431e522f8a87
My docker file looks like this:
FROM node:8.9.3
EXPOSE 3000
RUN mkdir -p src
WORKDIR /src
ADD . /src
RUN yarn install
RUN yarn build
CMD ["yarn", "run", "start:prod"]
APPLICATION SETTINGS
I've tried editing the Application Settings, to no avail, with the key/value pair: WEBSITES_PORT=3000
Apparently Azure only exposes ports 80 and 443 for inbound traffic:
80: Default port for inbound HTTP traffic to apps running in App Service Plans in an App Service Environment. On an ILB-enabled ASE, this port is bound to the ILB address of the ASE.
443: Default port for inbound SSL traffic to apps running in App Service Plans in an App Service Environment. On an ILB-enabled ASE, this port is bound to the ILB address of the ASE.
How do I expose port 3000 in an Azure App Service?
User 4c74356b41 is correct.
In APPLICATION SETTINGS you need to set the key / value pair WEBSITES_PORT.
For some reason it's not working on this image, but I went through another example and did it all through the command line, and it worked fine.
For me you would use a docker-compose.yml file to expose 3000 like so:
version: '3'
services:
servicename:
image: imagename
ports:
- '80:3000'

Resources