When I try to deploy a container using docker-compose, I get the following error:
testing |
testing | > test#1.0.0 start
testing | > npm-run-all --parallel start:server
testing |
testing |
testing | ERROR: "start:server" exited with 243.
testing exited with code 1
This only happens on any node:18.4.0 images. I have to use that node version.
My Dockerfile:
FROM node:18.4.0-alpine3.16
WORKDIR /app
COPY ./package.json ./
COPY ./package-lock.json ./
RUN npm install
COPY . /app
EXPOSE 80
CMD npm start
My docker-compose
version: '2'
services:
testing:
container_name: testing
build:
context: .
volumes:
- '.:/app'
ports:
- 80
- 9009:9009
My app (index.js):
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
My package.json
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "npm-run-all --parallel start:server",
"start:server": "nodemon .",
"start:web": "echo web starting"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.18.1",
"nodemon": "^2.0.18"
},
"devDependencies": {
"npm-run-all": "^4.1.5"
}
}
os: Ubuntu 20.04.4 LTS.
docker-compose: version 1.29.2
docker: Docker version 20.10.12, build 20.10.12-0ubuntu2~20.04.1
Maybe you found the problem, but this can help someone:
I was havin the same issue using node:bullseye image that comes with npm v8.13.0, so I updated it to the latest version (v8.15.1, in my case) an it was solved.
So, to keep using this image with the latest version, i put this in Dockerfile:
RUN npm install -g npm#latest
You have a volume mapping onto the /app path. That hides everything in that path in the image, including the npm packages you install when building your Dockerfile.
Also, your port mappings don't match your app. Your app listens on port 3000, so your should map port 3000 to a host port.
If you use this docker-compose file, it'll work.
version: '2'
services:
testing:
container_name: testing
build:
context: .
ports:
- 3000:3000
Then you can go to http://localhost:3000/ and you'll get your "Hello World!" message.
First of all, In your index.js you exposed port 3000 const port = 3000.
But on docker you exposed 80 and 3009
ports:
- 80
- 9009:9009
A tip - you don't have to COPY ./package.json ., you copied the entire folder into the container.
WORKDIR /app
COPY . /app
RUN npm install
EXPOSE 80
CMD npm start
Related
I am trying to deploy a containerized node-typescript-express app to cloud run but I am unable to do so, receiving the following error:
The user-provided container failed to start and listen on the port defined provided by the PORT=8080
Here is my Dockerfile config:
FROM node:18.13.0 as base
WORKDIR /home/node/app
COPY package*.json ./
RUN npm i
COPY . .
FROM base as production
ENV NODE_PATH=./dist
RUN npm run build
In my code, I'm declaring port as
const PORT = process.env.PORT || 8080;
I also have a .env file where I was setting port, but I deleted the port key - as far as I know, GCP cloud run injects the port variable anyway.
Here is a screenshot from my project settings on GCP. I uploaded my image by building it locally with docker-compose build, tagging it, and uploading it to the GCP container repository.
I've tried manually setting the port in the code, removing the env file completely, specifying a different port, etc. I'm not even sure if the port is specifically the error and it's just some kind of catch-all.
Here's my package.json:
{
"name": "weather-service",
"version": "0.0.0",
"description": "small node server that fetches openweather api data",
"engines": {
"node": ">= 18.12 <19"
},
"scripts": {
"start": "NODE_PATH=./dist node dist/src/index.js",
"clean": "rimraf coverage dist tmp",
"dev": "ts-node-dev -r tsconfig-paths/register src/index.ts",
"prebuild": "npm run lint",
"build": "ttsc -p tsconfig.release.json",
"build:watch": "ttsc -w -p tsconfig.release.json",
"build:release": "npm run clean && ttsc -p tsconfig.release.json",
"test": "jest --coverage --detectOpenHandles --forceExit",
"test:watch": "jest --watch --detectOpenHandles --forceExit",
"lint": "eslint . --ext .ts --ext .mts && tsc",
"lint:fix": "eslint . --ext .ts --ext .mts",
"prettier": "prettier --config .prettierrc --write .",
"prepare": "husky install",
"pre-commit": "lint-staged"
And lastly, here's my docker-compose file and how I'm executing the commands
docker-compose.yml
version: '3.7'
services:
weather-service:
build:
context: .
dockerfile: Dockerfile
target: base
volumes:
- ./src:/home/node/app/src
container_name: weather-service
expose:
- '8080'
ports:
- '8080:8080'
command: npm run dev
docker-compose.prod.yml
version: '3.7'
services:
weather-service:
build:
target: production
command: npm run start
docker.compose.dev.yml
version: '3.7'
services:
weather-service:
env_file:
- .env
environment:
- ${PORT}
- ${WEATHER_API_KEY}
Makefile
up:
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up
up-prod:
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up
down:
docker-compose down
build:
docker-compose build
If you are using Macbook, then below answer from Bk Lim in the below link might help you:
Cloud Run: "Failed to start and then listen on the port defined by the PORT environment variable." When I use 8080
Update: I managed to get it successfully deployed by changing my docker-compose files to a template I found on GitHub, here
My docker knowledge is minimal so if anyone has any idea why my old docker-compose wasn't working, I'd love to know.
When I go to run docker run -p 8080:3000 --name cabinfeverInstance -t something/cabinfever I get put into a Node.js REPL, when I expect to see "Listening on port: 3000". Going to localhost:8000 results in a "didn’t send any data. ERR_EMPTY_RESPONSE". I have found no other instances of this occurring (maybe I am not searching Google for the correct words/tricky phrases). I did find this issue which seems somewhat related. Their solution was to "make the containerized app expect requests from the windows host machine IP (not container IP)", but I am not sure how to implement that. Also, their solution could also not be my solution.
What I have tried:
Clean/purging the data.
Running docker run -p 8080:3000/tcp -p 8080:3000/udp --name cabinfeverInstance -t something/cabinfever
Not specifying the specific port (8080).
Specifying 0.0.0.0.
Several additional ideas.
None have worked and I still get the wonderful Node REPL.
If anyone has any suggestions, I would appreciate them.
Here are the relevant files:
index.js
var express = require('express');
var app = express();
var port = 3000;
app.get('/', function(req,res) {
console.log(new Date().toLocaleString());
res.send(new Date().toLocaleString());
});
app.listen(port, () => {
console.log(`Listening at http://localhost: ${port}`);
});
package.json:
{
"name": "docnode",
"version": "1.0.0",
"description": "barebones node on docker",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "index.js"
},
"author": "my.email.address#gmail.com",
"license": "MIT",
"dependencies": {
"express": "^4.15.5"
}
}
docker-compose.yml:
version: "3"
services:
node:
build: .
command: node index.js
ports:
- "3000:3000"
Dockerfile:
FROM node:slim
LABEL author="my.email.address#gmail.com"
WORKDIR /app
# copy code, install npm dependencies
COPY index.js /app/index.js
COPY package.json /app/package.json
RUN npm install
You should specify the command to run in the Dockerfile, not the docker-compose.yml file:
CMD ["node", "index.js"]
When you docker run an image, the only options it considers are those on the docker run command line. docker run doesn't know about docker-compose.yml, so if you specify things like command: there it won't be honored. Since the CMD isn't in the Dockerfile and it isn't on the docker run command line (after the image name), you fall back to the base image's CMD, which in the case of node is to run the REPL.
With this change you don't need to override command: in the docker-compose.yml file and you can delete that line. Running
docker-compose up -d
will start the container(s) in the docker-compose.yml file with the options specified there (note, the ports: mapping and the docker run -p ports are slightly different).
I have angular 8 as client side, server side as node and mysql as bd
server app is up on localhost:3000
node package.json:
"scripts": {
"start": "node src/index.ts",
"test": "echo \"Error: no test specified\" && exit 1",
"watch-changes": "nodemon --watch 'src/**/*' -e ts,tsx --exec ts-node src/index.ts"
},
angular just builds into dist folder and i use one from server side:
angular package.json:
"scripts": {
"ng": "ng",
"start": "ng serve --host 0.0.0.0",
"build": "ng build",
........
index.ts
app.use(express.static(join(__dirname, '../../file-manager/dist/file-manager')));
app.use(json());
app.use(urlencoded({extended: true}));
app.use('/api', new Router().routes);
app.all('/*', function(req, res, next) {
res.sendFile('index.html', { root: join(__dirname, '../../file-manager/dist/file-manager') });
});
app.use((err, req, res, next) => {
if(err) {
res.status(500).json({message: err.human || 'Internal Server Error'});
return next(err);
}
return next();
});
console.log('PORT IS ', port);
app.listen(port);
\file-manager.docker\dev.dockerfile
FROM node:10
RUN mkdir /usr/src/app
WORKDIR /usr/src/app
COPY package.json ./
RUN npm install
COPY . .
EXPOSE 4200
CMD ["npm", "start"]
\server.docker\dev.dockerfile
FROM node:10
RUN mkdir /usr/src/app
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "run", "watch-changes"]
When try docker-compose down and after docker-compose up:
version: '3'
services:
client:
build:
context: ./file-manager
dockerfile: .docker/dev.dockerfile
image: file-manager-client-dev
container_name: file-manager-client-dev
ports:
- "4000:4200"
volumes:
- ./file-manager/src:/usr/src/app/src
server:
build:
context: ./server
dockerfile: .docker/dev.dockerfile
image: file-manager-server-dev
container_name: file-manager-server-dev
ports:
- "8000:3000"
external_links:
- client
depends_on:
- mysql
mysql: # name of the third service
build:
context: ./mysql
dockerfile: .docker/dev.dockerfile
container_name: mysql-container
restart: always
ports:
- "3306:3306"
and enter http://localhost:8000/ I see
{"message":"Internal Server Error"}
on white page of browser
When I 'ng build' and 'npm run watch-changes' separately all works
docker-compose ps
file-manager-client-dev docker-entrypoint.sh npm start Up 0.0.0.0:4000->4200/tcp
file-manager-server-dev docker-entrypoint.sh npm r ... Up 0.0.0.0:8000->3000/tcp
mysql-container docker-entrypoint.sh mysqld Up 0.0.0.0:3306->3306/tcp, 33060/tcp
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
file-manager-client-dev latest 24d9f5c92c12 17 minutes ago 1.51GB
file-manager-server-dev latest 02b5dd9cac83 25 minutes ago 1.03GB
angular-8-file-manager_mysql latest 4191cb9d3c3f 26 minutes ago 437MB
node 10 a68faf70e589 4 days ago 904MB
node latest 977e59b234b7 4 days ago 908MB
mysql 5 cd3ed0dfff7e 5 days ago 437MB
logs
docker container logs file-manager-server-dev
[nodemon] 1.19.1
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: src/**/*
[nodemon] starting `ts-node src/index.ts`
Error: ENOENT: no such file or directory, stat '/usr/src/file-manager/dist/file-manager/index.html'
Error: ENOENT: no such file or directory, stat '/usr/src/file-manager/dist/file-manager/index.html'
docker tries find index.html in file-manager-server-dev image but need to look for in file-manager-client-dev, how to specify it? Help please
I read many threads sabout this but no one solves anything.
Some say you have to add --legacy-watch (or -L) to the nodemon command.
Others shows several different configurations and apparently nodody really knows what you gotta do to achieve server restarting when a file change at the volume inside a docker container.
Here my configuration so far:
Dockerfile:
FROM node:latest
# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
# install nodemon globally
RUN npm install nodemon -g
# Install dependencies
COPY package*.json ./
RUN npm install
# Bundle app source
COPY . /usr/src/app
# Exports
EXPOSE 3000
CMD ["npm", "start"]
docker-compose.yml
version: '3.1'
services:
node:
build: .
user: "node"
volumes:
- ./:/usr/src/app
ports:
- 3000:3000
depends_on:
- mongo
working_dir: /usr/src/app
environment:
- NODE_ENV=production
expose:
- "3000"
mongo:
image: mongo
expose:
- 27017
volumes:
- ./data/db:/data/db
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: example
package.json
{
"name": "node-playground",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon -L"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"ejs": "^2.7.1",
"express": "^4.17.1",
"mongoose": "^5.7.1"
},
"devDependencies": {
"nodemon": "^1.19.2"
}
}
I tried many different setups as well. Like not installing globally nodemon but only as a project dependency. And also running the command at the docker-compse.yml, and i believe many others I don't remember right now. Nothing.
If someone has any cetainty about this, please help. Thanks!!!!
Try it!
This worked for me:
Via the CLI, use either --legacy-watch or -L for short. More informations here.
I went ahead and created an example container and repo to show how you can achieve this..
Just follow the steps below, which outline how to use nodemon inside of a Docker container.
Docker Container: at DockerHub
Source Code: at GitHub
package.json:
{
"name": "nodemon-docker-test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start:express": "node ./index.js",
"start": "nodemon"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.17.1"
},
"devDependencies": {
"nodemon": "^1.19.2"
}
}
Dockerfile:
FROM node:slim
WORKDIR /app
COPY package*.json ./
RUN apt-get update
RUN npm install
COPY . /app
# -or-
# COPY . .
EXPOSE 1337
CMD ["npm", "start"]
docker-compose.yml: (if you are using it)
version: "3"
services:
nodemon-test:
image: oze4/nodemon-docker-test
ports:
- "1337:1337"
How to reproduce:
Step 1 USING DOCKER RUN: SKIP IF YOU ARE USING DOCKER COMPOSE (go to step 1 below if you are) pull down example docker container
docker run -d --name "nodemon-test" -p 1337:1337 oze4/nodemon-docker-test
Step 1 USING DOCKER-COMPOSE:
See the docker-compose.yml file above for configuration
cd /path/to/dir/that/has/your/compose/file
docker-compose up -d
Step 2: verify the app works
http://localhost:1337
Step 3: check the container logs, to get a baseline
docker logs nodemon-test
Step 4: I have included a bash script to make editing a file as simple as possible. We need to pop a shell on the container, and run the bash script (change.sh)
docker exec -it nodemon-test /bin/bash
bash change.sh
exit
Step 5: check the logs again to verify changes were made and that nodemon restarted
docker logs nodemon-test
As you can see by the last screenshot, nodemon successfully restarted after changes were made!
All right
Thanks a lot to MattOestreich for your answer.
Now i got it working, I don't know what it was, i did follow your set up but of course i'm using docker-compose and i also stripped some things out of it. I'm also not calling mongo image anymore since i setup the db in an Mongodb atlas cluster.
my actual config:
Dockerfile:
FROM node:12.10
WORKDIR /app
COPY package*.json ./
RUN apt-get update
RUN npm install
COPY . /app
EXPOSE 3000
CMD ["npm", "start"]
docker-compse.yml
version: '3.1'
services:
node:
build: .
volumes:
- ./:/app
ports:
- 3000:3000
working_dir: /app
expose:
- "3000"
package.json
{
"name": "node-playground",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.19.0",
"dotenv": "^8.1.0",
"ejs": "^2.7.1",
"express": "^4.17.1",
"mongoose": "^5.7.1"
},
"devDependencies": {
"nodemon": "^1.19.2"
}
}
thanks Matt again and i hope this thread helps people in need like me.
Nodemon depends on Chokidar and a potential solution is to make it use polling by setting CHOKIDAR_USEPOLLING environment variable to true.
For example you can do this in docker-compose.yml:
services:
api1:
build:
context: .
dockerfile: Dockerfile
volumes:
- /app/node_modules
- ${PWD}:/app
ports:
- 80:3000
environment:
- CHOKIDAR_USEPOLLING=true
Change in Docker file
CMD ["npm", "start"]
Change start script
"start": "nodemon -L server.js"
Build Command
docker build . -t <containername>
Use this command to run the docker container
docker run -v $(pwd):/app -p 8080:8080 -it <container Id>
-v = Volumes . the preferred mechanism for persisting data generated by and used by Docker containers.
/app = WORKDIR /app
$(pwd) = PWD is a variable set to the present working directory. So $(pwd) gets the value of the present working directory
I'm having trouble setting up chrome debugger within a dockerized node application.
I've tried following https://github.com/nodejs/node/issues/11591 to no success.
My application does run on PORT, but my chrome debugger always displays WebSockets request was expected when on localhost:9229. I have a suspicion that it has something to do with my index.js listening on PORT, but I'm unsure.
Can someone please help? Thanks!
(I have a .env file with DOCKER_WORKING_DIR and PORT defined.)
Dockerfile
FROM node:8
ENV DOCKER_WORKING_DIR="/usr/local/app"
WORKDIR ${DOCKER_WORKING_DIR}
COPY package.json .
COPY package-lock.json .
RUN npm install --quiet
COPY . .
CMD ["npm", "run", "start"]
docker-compose.yml
version: '2.2'
services:
api:
build:
context: ../../.
dockerfile: docker/images/app/Dockerfile
command: npm run start-dev
environment:
PORT: ${PORT}
DOCKER_WORKING_DIR: ${DOCKER_WORKING_DIR}
volumes:
- ../../.:${DOCKER_WORKING_DIR}/
- ${DOCKER_WORKING_DIR}/node_modules
ports:
- "${PORT}:${PORT}"
- 9229:9229
package.json
"scripts": {
"start": "node index.js",
"start-dev": "nodemon --watch ./src -x \"npm run start-debug\"",
"start-debug": "node --inspect=0.0.0.0:9229 index.js",
},
index.js
const server = require('./src/server');
server.listen(process.env.PORT);
Answering my own question. I used a node inspector chrome extension and then everything worked https://chrome.google.com/webstore/detail/nodejs-v8-inspector-manag/gnhhdgbaldcilmgcpfddgdbkhjohddkj?hl=en