简体   繁体   中英

"Dockerized" Node.js Application Not Responding to Host

I am trying to "Dockerize" a rather large, complicated Node.js application, which is roughly structured like so:

Nebula [root directory of the project; runs the Node.js application]

|__CosmosD3 [directory that contains all HTML and JS files]

|__Nebula-Pipeline [directory that contains most Python files that do all the heavy computations]

Our standard installation process for this project is rather complicated due to all the interconnected pieces that all must work together flawlessly to enable our front end JS files to communicate with our back end Python scripts. For Linux/Unix systems, this is the rough process (with commands run from within the Nebula directory):

  1. Install Java. (Just about any version should do; we have a single Java file that needs to be run for a particular interaction in the front end)
  2. Install Python 2.7 and pip
  3. Run pip install --upgrade pip to ensure the latest pip is being used
  4. Install Node.js, npm, and zmq using sudo apt-get install libzmq-dev npm nodejs-legacy
  5. Run npm install to install our Node.js package dependencies
  6. Run pip install -e ./Nebula-Pipeline to install all Python dependencies
  7. Pray that everything has gone smoothly and run the application with npm start . The default port is 8081 , so the application should be accessible through localhost:8081 .

A very similar project to this one has already been "Dockerized." By tweaking the Dockerfile for the other project to more closely correspond to the steps above, this is the Dockerfile I've created:

FROM ubuntu:16.04

RUN mkdir /www
WORKDIR /www
RUN apt-get update

RUN apt-get install -y libzmq-dev npm nodejs-legacy python python-pip
RUN apt-get update && \
    apt-get install -y openjdk-8-jdk && \
    apt-get install -y ant && \
    apt-get clean;

# Fix certificate issues, found as of 
# https://bugs.launchpad.net/ubuntu/+source/ca-certificates-java/+bug/983302
RUN apt-get update && \
    apt-get install ca-certificates-java && \
    apt-get clean && \
    update-ca-certificates -f;

# Setup JAVA_HOME, this is useful for docker commandline
ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64/
RUN export JAVA_HOME

##COPY ./lib/ /opt/lib

RUN pip install --upgrade pip
COPY ./Nebula /www
RUN ls -a /www
RUN npm install

RUN pip install -e /www/Nebula-Pipeline

EXPOSE 8081

CMD ["npm", "start"]

When I run this Dockerfile with docker build -t nebulaserver , it appears that the image is created successfully. When I run the image with docker run -p 8081:8081 nebulaserver , I get the following printout that seems to indicate that everything is actually working properly. (Note that the "PORT: 8081" printout is a confirmation of the port that the Node.js app is using.)

Michelles-MacBook-Pro-8$ docker run -p 8081:8081 nebulaserver

> Nebula@0.0.1 start /www
> node app.js

PORT:
8081

However, when I subsequently try to connect to localhost:8081 , I don't get any kind of response. Additionally, I expect to see additional printouts from my Node.js server when it receives a request for one of the HTML pages. I don't see any of these printouts either. It's as if the port forwarding is not working properly. Based on everything I've read, I should be doing things correctly, but I've never used Docker before, so perhaps I'm missing something?

Anyone have any idea what I might be doing wrong?

EDIT: Here's my app.js file, in case that helps figure out what's going on...

/*Import packages required in package.json   */
/*Add these packages from the ../node_modules path*/
var express = require('express');//A lightweight nodejs web framework
var path = require('path');//Ability to join filepaths to filenames.
var favicon = require('serve-favicon');//Set prefered icon in browser URL bar. Unused?
var logger = require('morgan');//HTTP request logger. Unused?
var cookieParser = require('cookie-parser');//Stores cookies in req.cookies
var bodyParser = require('body-parser');//Middleware parser for incoming request bodies, 

/* REST API routes */
var routes = require('./routes/index');//Points to /routes/index.js.  Currently, index.js points to CosmosD3/CosmosD3.html

/* Connect to the databases */
//var mongo = require('mongodb');
//var monk = require('monk');
//var db = monk('localhost:27017/nodetest');
//var datasets = monk('localhost:27017/datasets');

/* The HTTP request handler */

var app = express();//Creates app from express class. (Baseline famework for an app. No web functionality).
var debug = require('debug')('Nebula:server');//Require the debug module. Pass it scoping 'Nebula:server'
var http = require('http').Server(app);//Create an http server on top of app.

/* The Socket.io WebSocket module */
var io = require('socket.io')(http);//Create an io/websocket on top of http object.

/* Our custom Nebula module handles the WebSocket synchronization */
var nebula = require('./nebula')(io);//Creates nebula layer on top of io.

/* Set the port we want to run on */
var port = process.env.PORT || 8080;
//app.set('port', port);
var host = '0.0.0.0';
app.listen(port, host);
console.log(`Running on http://${host}:${port}`);

/* view engine setup, currently not used */
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());

/* Expose everything in public/ through our web server */
app.use(express.static(path.join(__dirname, 'public')));
app.use("/cosmos", express.static(path.join(__dirname, 'CosmosD3')));

// Make our db accessible to our router
//app.use(function(req, res, next){
//    req.db = db;
//    req.datasets = datasets;
//    next();
//});

/* Initiate the REST API */
app.use('/', routes);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});

/**
 * Event listener for HTTP server "error" event.
 */

function onError(error) {
  if (error.syscall !== 'listen') {
    throw error;
  }

  var bind = (typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port);

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case 'EACCES':
      console.error(bind + ' requires elevated privileges');
      process.exit(1);
      break;
    case 'EADDRINUSE':
      console.error(bind + ' is already in use');
      process.exit(1);
      break;
    default:
      throw error;
  }
}

/**
 * Event listener for HTTP server "listening" event.
 */

function onListening() {
  var addr = http.address();
  var bind = (typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port);
  debug('Listening on ' + bind);
}

/**
 * Listen on provided port, on all network interfaces.
 */
http.listen(port);
http.on('error', onError);
http.on('listening', onListening);

I have had this problem before and (as mentioned by @davidmaze in his comment ) I had to change the host that my app was listening on. In my case, it was that I was using the Express framework , which (despite the docs implying otherwise) was listening only for localhost ( 127.0.0.1 ), and I needed it to listen to 0.0.0.0 . See lines 58- 66 (which make up the 2nd code block in the Create the Node.js app section of the Dockerizing a Node.js web app example) for where they explicitly tell express to listen for 0.0.0.0 .

I finally figured it out!! After a ton of digging around, I discovered that the default IP for Docker applications is http://192.168.99.100 as opposed to http://localhost . I got the answer from here:

https://forums.docker.com/t/docker-running-host-but-not-accessible/44082/13

I am trying to "Dockerize" a rather large, complicated Node.js application, which is roughly structured like so:

Nebula [root directory of the project; runs the Node.js application]

|__CosmosD3 [directory that contains all HTML and JS files]

|__Nebula-Pipeline [directory that contains most Python files that do all the heavy computations]

Our standard installation process for this project is rather complicated due to all the interconnected pieces that all must work together flawlessly to enable our front end JS files to communicate with our back end Python scripts. For Linux/Unix systems, this is the rough process (with commands run from within the Nebula directory):

  1. Install Java. (Just about any version should do; we have a single Java file that needs to be run for a particular interaction in the front end)
  2. Install Python 2.7 and pip
  3. Run pip install --upgrade pip to ensure the latest pip is being used
  4. Install Node.js, npm, and zmq using sudo apt-get install libzmq-dev npm nodejs-legacy
  5. Run npm install to install our Node.js package dependencies
  6. Run pip install -e ./Nebula-Pipeline to install all Python dependencies
  7. Pray that everything has gone smoothly and run the application with npm start . The default port is 8081 , so the application should be accessible through localhost:8081 .

A very similar project to this one has already been "Dockerized." By tweaking the Dockerfile for the other project to more closely correspond to the steps above, this is the Dockerfile I've created:

FROM ubuntu:16.04

RUN mkdir /www
WORKDIR /www
RUN apt-get update

RUN apt-get install -y libzmq-dev npm nodejs-legacy python python-pip
RUN apt-get update && \
    apt-get install -y openjdk-8-jdk && \
    apt-get install -y ant && \
    apt-get clean;

# Fix certificate issues, found as of 
# https://bugs.launchpad.net/ubuntu/+source/ca-certificates-java/+bug/983302
RUN apt-get update && \
    apt-get install ca-certificates-java && \
    apt-get clean && \
    update-ca-certificates -f;

# Setup JAVA_HOME, this is useful for docker commandline
ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64/
RUN export JAVA_HOME

##COPY ./lib/ /opt/lib

RUN pip install --upgrade pip
COPY ./Nebula /www
RUN ls -a /www
RUN npm install

RUN pip install -e /www/Nebula-Pipeline

EXPOSE 8081

CMD ["npm", "start"]

When I run this Dockerfile with docker build -t nebulaserver , it appears that the image is created successfully. When I run the image with docker run -p 8081:8081 nebulaserver , I get the following printout that seems to indicate that everything is actually working properly. (Note that the "PORT: 8081" printout is a confirmation of the port that the Node.js app is using.)

Michelles-MacBook-Pro-8$ docker run -p 8081:8081 nebulaserver

> Nebula@0.0.1 start /www
> node app.js

PORT:
8081

However, when I subsequently try to connect to localhost:8081 , I don't get any kind of response. Additionally, I expect to see additional printouts from my Node.js server when it receives a request for one of the HTML pages. I don't see any of these printouts either. It's as if the port forwarding is not working properly. Based on everything I've read, I should be doing things correctly, but I've never used Docker before, so perhaps I'm missing something?

Anyone have any idea what I might be doing wrong?

EDIT: Here's my app.js file, in case that helps figure out what's going on...

/*Import packages required in package.json   */
/*Add these packages from the ../node_modules path*/
var express = require('express');//A lightweight nodejs web framework
var path = require('path');//Ability to join filepaths to filenames.
var favicon = require('serve-favicon');//Set prefered icon in browser URL bar. Unused?
var logger = require('morgan');//HTTP request logger. Unused?
var cookieParser = require('cookie-parser');//Stores cookies in req.cookies
var bodyParser = require('body-parser');//Middleware parser for incoming request bodies, 

/* REST API routes */
var routes = require('./routes/index');//Points to /routes/index.js.  Currently, index.js points to CosmosD3/CosmosD3.html

/* Connect to the databases */
//var mongo = require('mongodb');
//var monk = require('monk');
//var db = monk('localhost:27017/nodetest');
//var datasets = monk('localhost:27017/datasets');

/* The HTTP request handler */

var app = express();//Creates app from express class. (Baseline famework for an app. No web functionality).
var debug = require('debug')('Nebula:server');//Require the debug module. Pass it scoping 'Nebula:server'
var http = require('http').Server(app);//Create an http server on top of app.

/* The Socket.io WebSocket module */
var io = require('socket.io')(http);//Create an io/websocket on top of http object.

/* Our custom Nebula module handles the WebSocket synchronization */
var nebula = require('./nebula')(io);//Creates nebula layer on top of io.

/* Set the port we want to run on */
var port = process.env.PORT || 8080;
//app.set('port', port);
var host = '0.0.0.0';
app.listen(port, host);
console.log(`Running on http://${host}:${port}`);

/* view engine setup, currently not used */
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());

/* Expose everything in public/ through our web server */
app.use(express.static(path.join(__dirname, 'public')));
app.use("/cosmos", express.static(path.join(__dirname, 'CosmosD3')));

// Make our db accessible to our router
//app.use(function(req, res, next){
//    req.db = db;
//    req.datasets = datasets;
//    next();
//});

/* Initiate the REST API */
app.use('/', routes);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});

/**
 * Event listener for HTTP server "error" event.
 */

function onError(error) {
  if (error.syscall !== 'listen') {
    throw error;
  }

  var bind = (typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port);

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case 'EACCES':
      console.error(bind + ' requires elevated privileges');
      process.exit(1);
      break;
    case 'EADDRINUSE':
      console.error(bind + ' is already in use');
      process.exit(1);
      break;
    default:
      throw error;
  }
}

/**
 * Event listener for HTTP server "listening" event.
 */

function onListening() {
  var addr = http.address();
  var bind = (typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port);
  debug('Listening on ' + bind);
}

/**
 * Listen on provided port, on all network interfaces.
 */
http.listen(port);
http.on('error', onError);
http.on('listening', onListening);

On a MAC, I had to put in the port in two spots:

  1. in the Dockerfile I needed to put in: EXPOSE 5000 5010 5011
    before the CMD line (second to last line) and it exposes 3 ports

  2. In docker-compose.yml (I have two dockers) I need to put in at the app part: ports:

  • "5000:5000"
  • "5010:5010"
  • "5011:5011"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM