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.
Related
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'
I am trying to dockerize both a frontend made with create-react-app and its express API backend.
The docker containers sit on ec2 instances. I have tried several tutorials and also threads here on stackoverflow, but I can't work out what is going wrong.
The error I get is:
Could not find an open port at ec2-x-xx-xx-xxx.eu-west-2.compute.amazonaws.com.
this refers to my .env file which contains only
HOST= ec2-x-xx-xx-xxx.eu-west-2.compute.amazonaws.com
my Dockerfile for the front end is as follows:
FROM node:12-alpine
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install --silent
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
whereas the backend's:
FROM node:12-alpine as builder
WORKDIR /app
COPY package.json /app/package.json
RUN npm install
COPY . /app
EXPOSE 3001
CMD ["node", "app.js" ]
I need the backend to run on port 3001 and the frontend to run on 3000. The frontend is bound to the backend api via the proxy line in package.json, where I have placed:
"proxy":"http://ec2-x-xx-xx-xxx.eu-west-2.compute.amazonaws.com:3001",
Both containers build fine. However, running the backend with docker run -p 3001:3001 server and then docker run -p 3000:3000 client spits the error
Attempting to bind to HOST environment variable: ec2-x-xx-xx-xxx.eu-west-2.compute.amazonaws.com
If this was unintentional, check that you haven't mistakenly set it in your shell.
Learn more here: https://xxx.xx/xxx-advanced-config
Could not find an open port at ec2-x-xx-xx-xxx.eu-west-2.compute.amazonaws.com.
Network error message: listen EADDRNOTAVAIL: address not available 10.xx.0.xxx
I have tried running only the server side and then running npm start from my local machine, it works. The problem seems to have to do with docker networking between containers.
I also tried running the server side with the command
docker run -p 10.xx.0.xxx:3000:3000 client
to make sure the client pings the right ip address, however this didn't work.
Could anyone give me some direction please?
If you need more info on the source code, please just leave a comment, I didn't want to clutter the thread by making it longer than it already is..
Thank you
I have a simple node.js - express app and I set the listening port to 3000.
On my Dockerfile I expose port 3000 and run the container using -p 3000:3000.
I want to deploy my app on Heroku using my docker image, what is the proper way of doing it?
I am aware that in these cases we use process.env or specify a global variable in a .env file.
I list below my Dockerfile.
FROM node:10-alpine as builder
ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}
RUN apk --no-cache add python make g++
COPY package*.json ./
RUN npm install --only=production
# RUN npm ci --only=production
FROM node:10-alpine
WORKDIR /usr/src/app
COPY --from=builder node_modules node_modules
COPY . .
EXPOSE 3000
CMD [ "npm", "run", "start:prod" ]
What is the proper way of approaching the problem?
Plus any suggestions for improving my Dockerfile are more than welcomed.
When deploying a web application on Heroku they will tell you which port is free through an env variable. You have to bind that port in your source code.
In your Dockerfile remove EXPOSE 3000 since you cannot open a custom port.
In your source code you will have to write something like const port = process.env.PORT || 3000.
So when you are executing your program locally and you don't have the env var $PORT set it will open the port 3000. On Heroku it will open the port on what is specified in $PORT.
A common hurdle when deploying on Heroku is that your URLs are no longer working. When running locally you might have the URL: http://localhost:3000/ but on Heroku you have: https://my-app.herokuapp.com/.
https can cause a bit of headache since you might have been working with http the whole time. Furthermore if you hardcoded the port at the end of the hostname it is going to cause some problems. Heroku automatically translates a hostname into an ip-address + port.
You can read here about deploying on Docker here:
https://devcenter.heroku.com/categories/deploying-with-docker
https://devcenter.heroku.com/articles/build-docker-images-heroku-yml
When you've made sure that your code is Heroku compatible you can start doing the Heroku Docker deployment. The article is very thorough and I believe it is better if you read them than me just copy pasting what it says there.
I am very to new Docker so please pardon me if this this is a very silly question. Googling hasn't really produced anything I am looking for. I have a very simple Dockerfile which looks like the following
FROM node:9.6.1
RUN mkdir /usr/src/app
WORKDIR /usr/src/app
ENV PATH /usr/src/app/node_modules/.bin:$PATH
# install and cache app dependencies
COPY package.json /usr/src/app/package.json
RUN npm install --silent
COPY . /usr/src/app
RUN npm start
EXPOSE 8000
In the container the app is running on port 8000. Is it possible to access port 8000 without the -p 8000:8000? I just want to be able to do
docker run imageName
and access the app on my browser on localhost:8000
By default, when you create a container, it does not publish any of its ports to the outside world. To make a port available to services outside of Docker, or to Docker containers which are not connected to the container’s network, use the --publish or -p flag. This creates a firewall rule which maps a container port to a port on the Docker host.
Read more: Container networking - Published ports
But you can use docker-compose to set config and run your docker images easily.
First installing the docker-compose. Install Docker Compose
Second create docker-compose.yml beside the Dockerfile and copy this code on them
version: '3'
services:
web:
build: .
ports:
- "8000:8000"
Now you can start your docker with this command
docker-compose up
If you want to run your services in the background, you can pass the -d flag (for “detached” mode) to docker-compose up -d and use `docker-compose ps to see what is currently running.
Docker Compose Tutorial
Old question but someone might find it useful:
First get the IP of the docker container by running
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container_name_or_id
Then connect to it from the the browser or using curl using the IP and port exposed :
Note that you will not be able to access the container on 0.0.0.0 because port is not mapped
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'