Why does my app listen on port 80 instead of port 3000 as I set it running inside docker container? - node.js

What I'm trying?
I'm trying to run my nodejs app inside a docker container and want to use it outside of the container(through my browser on port 3000).
DockerFile
FROM node:8
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
RUN npm run build
COPY . .
EXPOSE 3000
CMD [ "npm", "start" ]
app.ts(Relevant portion)
const port = process.env.port || 3000;
let app = express();
app.listen(port, () => {
console.log(`Listening on port ${port}!`);
});
command I'm using to run
$ docker run --net=host <imgName>
OS --> Windows 7
And in the Oracle Virtual Box I've changed network settings to bridged networks.
The command runs successfully and the server starts listening on port 80. And I can access it from outside the container on port 80 through postman,curl,browser,etc.
Where I am doing wrong? How can I make it to listen on port 3000? And also how is it even able to listen on port if I haven't exposed it explicitly?
I think the docker is passing port as an environment variable and setting it to 80 as I am not passing any environment variable myself.
Please help I'm very new to docker.

Just exposing in your Dockerfile won't do it for you. You will need to map it when you do docker run or execute using docker-example.yaml.
To achieve that you will need to use $ docker run -p 3000:3000. Following that you won't need to use --net=host that should be the reason why the service is available on port 80.
Hope it helps!
Cheers!

Related

Cannot access a Node.js server when hostname set to 127.0.0.1 but works for 0.0.0.0 [duplicate]

This question already has answers here:
Docker app server ip address 127.0.0.1 difference of 0.0.0.0 ip
(2 answers)
Closed 8 months ago.
I am trying to dockerize a Node.js server.
I use the following index.js and Dockerfile files:
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
FROM node:latest
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm i
COPY . .
EXPOSE 3000
CMD ["node", "index.js"]
Then I run docker build . -t webapp and docker run -p 8080:3000 webapp, but when I try to open the app in the browser I see "The webpage at http://localhost:8080/ might be temporarily down or it may have moved permanently to a new web address."
Then when I change the hostname in the index.js to 0.0.0.0, it seems to work fine and I can access my app in the browser under http://localhost:8080/.
What is the difference between running an app in a container on the localhost vs. on 0.0.0.0?
In a container, localhost is the container itself. So when you bind to 127.0.0.1 your program will only accept connections coming from inside the container.
You need to bind to 0.0.0.0 for it to accept connections from outside the container.

Docker container does not respond to http request

I'm trying to send an http request through axios, from my localhost (node server) to a docker container (which contains a simple server in node too) which belongs to a docker network, and identified by an specific IP.
I have used postman, xmlhttprequests, and axios but nothing seems to work. I have also tried with get and post requests but any of those get any answer from the container side.
Do you have any Idea of what am I doing wrong?
the .sh file that Im running to launch the container is:
docker build -t connectimg .
docker network create --subnet=119.18.0.0/16 mynet
docker run -d --name instance2 -p 4002:4000 --net mynet --ip 119.18.0.2 connectimg
and the docker logs result for the instance post-launch is:
{
lo: [
{
address: '127.0.0.1',
netmask: '255.0.0.0',
family: 'IPv4',
mac: '00:00:00:00:00:00',
internal: true,
cidr: '127.0.0.1/8'
}
],
eth0: [
{
address: '119.18.0.2',
netmask: '255.255.0.0',
family: 'IPv4',
mac: '02:42:77:12:00:02',
internal: false,
cidr: '119.18.0.2/16'
}
]
}
Example app listening on port 3000
My Docker Instance Node app code is:
const express = require('express')
const app = express()
const port = 3000
const cors = require('cors')
var os = require('os');
app.use(cors());
app.use(express.json());
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
app.get('/listen', (req,res) => {
console.log('got it');
})
var networkInterfaces = os.networkInterfaces();
console.log(networkInterfaces);
And my Node server piece of code responsible of sending the get request to the instance is:
const connect = (req,res) => {
axios.get('http://119.18.0.2:3000/listen').then(resp => {
console.log(resp.data);
});
}
and the error I keep getting is:
ETIMEDOUT 119.18.0.2:3000
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1159:16)
Firstly, your URI http://119.18.0.2:3000/listen is incorrect. The docker network cannot be accessed directly as it is not a network that the host knows of.
The option -p 4002:4000 is what is exposing your docker container to the host(and the network you're connected to). 4002 is the port exposed to the host and port 4000 is the port your container is exposing INSIDE the docker network
To access the container from the host your URI would become http://localhost:4002/listen
To access the container from a different machine on the same network the URI would become http://<ip-address-of-this-machine>:4002/listen. You can find your IP using ipconfig in command prompt on Windows, or ifconfig in terminal on Linux based systems.
Secondly, your port allocations are mismatched. You set the port in your node app using const port = 3000 and exposed port 4000 of the container using -p 4002:4000 in your docker run command.
Either change your node application to expose port 4000 using const port = 4000
OR
Change your docker run command to expose port 3000 of the container by using -p 4002:3000.
Docker networks can be a bit confusing at first. Read up on them or check the documentation(hella useful), it will serve you well in future development. :)
EDIT: You can properly containerize your node application using a DockerFile similar to this:
FROM node:lts-alpine3.15
LABEL maintainer="MyDevName"
WORKDIR /usr/app
COPY ./myNodeApp ./
RUN npm install
CMD ["npm", "start"]
So that your node app runs automatically on start.
the .sh file that Im running to launch the container is:
docker build -t connectimg .
docker network create --subnet=119.18.0.0/16 mynet
docker run -d --name instance2 -p 4002:4000 --net mynet --ip 119.18.0.2 connectimg
if will leverage docker-compose, you might not need the script.
I'm trying to send an http request through axios, from my localhost (node server) to a docker container (which contains a simple server in node too) which belongs to a docker network, and identified by an specific IP.
seems like 2 things need to be tweaked:
use 0.0.0.0:4200 in the dockerized server.
verify the network that you associate with the container is reachable from your host operating system. if the docker network is not that important, you can just ditch it

Is this dockerfile set correctly to serve a React.js build on port 5000?

I have a React.js app which I have dockerized and it was working fine until yesterday when there was some kind of an error which I found out is due to node version 17 so I decided to get the docker image's node version back to 16. All good, but since I did this, I cannot get the docker image to run on the specified port.
Here is my dockerfile:
ROM node:16.10-alpine as build
RUN mkdir /app
WORKDIR /app
COPY /front-end/dashboard/package.json /app
RUN npm install
COPY ./front-end/dashboard /app
RUN npm run build
# Install `serve` to run the application.
RUN npm install -g serve
# Set the command to start the node server.
CMD serve -s -n build
# Tell Docker about the port we'll run on.
EXPOSE 5000
As you can see, I am making a build which I then serve on port 5000 but for some reason that does not work anymore and it used to work fine.
All I can see as an output in docker is:
Serving! │
│ │
│ - Local: http://localhost:3000 │
│ - On Your Network: http://172.17.0.2:3000
When I go to localhost:3000 nothing happens which is fine but it should be working on port 5000 and it does not run there. Any idea why I cannot run the docker image's build on port 5000 as I used to do before?
I use docker run -p 5000:5000 to run it on port 5000 but this does not solve the problem.
I faced issues at work due to this exact same scenario. After a few hours of looking through our companies deployment pipeline, I discovered the culprit...
The serve package.
They changed the default port from 5000 to 3000.
Source: serve github releases
So, to fix your issue, I recommend to add -l 5000 in your serve cmd.
From the logs you can see that your application might be listening for traffic on localhost:3000. Your EXPOSE 5000 line does not change that behaviour but makes Docker (and other users) think port 5000 is important. Since nothing is listening on port 3000 obviously you should get a 'connection refused'. You may want to lookup https://docs.docker.com/engine/reference/builder/#expose
To get out of that situation:
ensure your dockerized process is listening to 0.0.0.0:5000. You will have to add -l tcp://0.0.0.0:5000to your CMD line (see https://github.com/vercel/serve/blob/main/bin/serve.js#L117)
When running the container, ensure you expose the port by using docker run -p 5000:5000 ...
If need be tell your docker host's firewall to allow traffic to <ip>:5000
Now if you connect to http://<ip>:5000 you should see the application's response.
Your app is listening on port 3000. So you need to map whatever port you want to use on the host to port 3000. If you want to use port 5000, you should use -p 5000:3000. Then you should be able to access it using localhost:5000 on the host machine.
You should think of containers as separate machines from the host. So when the container says that it's listening on localhost:3000, that means localhost in the context of the container. Not the host.

What is port 49160 in docker-run?

I am following this tutorial to set up docker for my node.js rest api and there is this line in the tutorial:
docker run -p 49160:8080 -d <your username>/node-web-app
And this description:
The -p flag redirects a public port to a private port inside the
container. Run the image you previously built:
From the description, I know that port 49160 is a public port and 8080 is a private port. Since I am exposing port 5001 in my nodejs app, so I think I am running:
docker run -p 49160:5001 -d <your username>/node-web-app
But what exactly is a public port? Why is it "49160"?
It can be anything. Tutorial just used a random port. You can change it whatever you want. Then you can access your node-web-app running inside container at port 5001 at localhost:49160 from your host machine.
In your example port 8080 leads to some server (probably web server / Node) located inside of your Docker container. The outside (the host you're working on) port is 49160. The Docker setting named -p connects the inner port 8080 to the outer port 49160. If you now open the browser in your host system and hit the url http://localhost:49160 you will essentially access port 8080 inside the container.
Port 8080 is usually used for web servers. It is not obligatory though.
Port 49160 is just some port you or the auther of the tutorial decided to take as an example.
If you have a server inside the container listening on port 5001 it will not be accessible in your setup. If you want to make it accessible, you could adapt the following command:
docker run -p 49160:8080 -p 49159:5001 -d <your username>/node-web-app

Docker node.js app not listening on port

I'm working on a node.js web application and use localhost:8080 to test it by sending requests from Postman. Whenever I run the application (npm start) without using Docker, the app works fine and listens on port 8080.
When I run the app using Docker, The app seems to be running correctly (it displays that it is running and listening on port 8080), however it is unreachable using Postman (I get the error: Could not get any response). Do you know what the reason for this could be?
Dockerfile:
FROM node:8
WORKDIR /opt/service
COPY package.json .
COPY package-lock.json .
RUN npm i
COPY . .
EXPOSE 8080
CMD ["npm", "start"]
I build and run the application in Docker using:
docker build -t my-app .
docker run my-app
I have tried binding the port as described below, but I also wasn't able to reach the server on port 8181.
docker run -p 8181:8080 my-app
In my application, the server listens in the following way (using Express):
app.listen(8080, () => {
console.log('listening on port 8080');
})
I have also tried using:
app.listen(8080, '0.0.0.0', () => {
console.log('listening on port 8080');
})
The docker port command returns:
8080/tcp -> 0.0.0.0:8181
Do you guys have nay idea what the reason for this could be?
UPDATE: Using the IP I obtained from the docker-machine (192.168.99.100:8181) I was able to reach the app. However, I want to be able to reach it from localhost:8181.
The way you have your port assignment setup requires you to use the docker machine's ip address, not your localhost. You can find your docker machines ip using:
docker-machine ip dev
If you want to map the container ip to your localhost ports you should specify the localhost ip before the port like this:
docker run -p 127.0.0.1:8181:8080 my-app
Similar question:

Resources