Simple example of Vagrantfile / Dockerfile to run node app - node.js

I'm having difficulty trying to get a simple node app running inside a docker container hosted using vagrant.
This page explains the basic approach: https://www.vagrantup.com/blog/feature-preview-vagrant-1-6-docker-dev-environments.html
What I am unable to do is access the node app from my machine - in theory I believe I should be able to see my "hello world" style node/express app at localhost:8181...
Below is what I have so far:
Vagrantfile:
Vagrant.configure("2") do |config|
config.vm.provider "docker" do |d|
d.build_dir = "."
d.ports = ["8080:5000"]
# Is this necessary if EXPOSE is used in Dockerfile?
d.expose = ["5000"]
d.remains_running = true
d.volumes = ["/shared"]
end
config.vm.network "forwarded_port", guest: 8080, host: 8181
config.vm.synced_folder "~/Documents/shared", "/shared"
end
Dockerfile:
# DOCKER-VERSION 0.8.0
FROM centos:6.4
RUN rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
RUN yum install -y npm ImageMagick
ADD . /app
# Not necessary because node_modules are bundled
# RUN cd /app; npm install
EXPOSE 5000
CMD ["node", "/app/index.js"]
I've followed the documentation as closely as possible but just can't seem to achieve what I'm after. Any ideas?
Note: node app is working when running normally ie $ node index and accessed at localhost:5000
Thanks in advance
EDIT:
index.js:
var express = require('express'),
http = require('http');
var app = express();
var port = 5000;
app.get('/', function(req, res) {
res.send('Hello World');
});
var server = http.createServer(app);
server.on('listening', function() {
console.log('Express server listening on port ' + port);
});
server.listen(port, '0.0.0.0');
setInterval(function(){
console.log('running');
}, 5000);
package.json:
{
"name": "vagrant-docker-node",
"version": "0.0.0",
"dependencies": {
"express": "^4.1.0"
},
"main": "index.js"
}

I actually ran into the same issue. Not sure if it's intended behavior or bug but setting forwarded_port in a Vagrantfile with a Docker provider does nothing on the host boot2docker machine.
Unless I'm missing something, you have to either provide your own host machine with another Vagrantfile opening the correct ports or modify the one provided by Vagrant.
Approach 1: Provide your own host machine (based on boot2docker)
Here's the base Vagrantfile for the boot2docker host: boot2docker Vagrantfile. You need to edit a copy of this Vagrantfile and set your forwarded ports here.
Then, in your Docker app Vagrantfile, modify as follow:
config.vm.provider "docker" do |d|
# Specify here the path to the updated host Vagrantfile
d.vagrant_vagrantfile = "../boot2docker/Vagrantfile"
... # edited out for clarity
end
Make sure you point to your updated host machine. Here I set it to an upper level shared directory because if you want to share this machine between multiple Docker apps with seperate Vagrantfiles, you'll have to point to the same host Vagrantfile (otherwise it'll try to spin up new host VMs).
Approach 2: Update Vagrant's host machine
You can also update the Vagrantfile automatically used by Vagrant which is located in %VAGRANT_HOME%/data/docker-host/Vagrantfile. Modify the file to open your ports.
Then do a vagrant global-status to get the ID of the host machine and vagrant reload machineId to restart the machine which will trigger the port re-open and update.
I'm not sure if there's a better or sanctionned way to do this but that's the only way I could have the ports forwarded all the way from Docker container to physical machine.

Shouldn't you forward the exposed port 5000 from Docker to your host, using Vagrant?
config.vm.network "forwarded_port", guest: 5000, host: 8181
(to get your app reachable on port 8181 from your host browser, for example)
Instead of:
config.vm.network "forwarded_port", guest: 8080, host: 8181
Flows/redirects summary:
Docker container Vagrant VM Your computer
:8080 => :5000 => :8181

What's your host OS (the one you execute the "vagrant" command on)? If it's non-Linux (e.g. OSX or Windows) then your Docker container will be riding on top of a Linux VM (usually TinyCore Linux inside VirtualBox), and the port forwarding will be done from inside that VirtualBox into the Docker container.
You should see evidence of port forwarding taking effect by looking for listening TCP sockets using "netstat -tlpn" (on Linux) or "netstat -an" (on OSX)

Related

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

Node Debug From Vagrant

Unable to remote debug a node server running on a Vagrant box in Chrome from my host machine. The server is configured to run on port 8123.
Node Version: 7.10.0
In Vagrantfile:
config.vm.network :forwarded_port, host: 9229, guest: 9229
config.vm.network :forwarded_port, host: 8123, guest: 8123
From my vagrant box I run:
$ node --inspect index.js
Debugger listening on port 9229.
Warning: This is an experimental feature and could change at any time.
To start debugging, open the following URL in Chrome:
chrome-devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=127.0.0.1:9229/84085f07-dc42-4e1e-bdd8-532e6dc5c4c6
--- Customer Service---
Connecting to customer repository...
Connected. Starting server...
Server started successfully, running on port 8123.
When I try to access the url in Chrome from my host machine while I don't get an error the sources tab is empty.
Screenshot of devTools
Based on NodeJS 11591 issue. You can't access the Vagrant stuff via localhost (127.0.0.1), so you need to to specify host explicitly:
$ node --inspect=0.0.0.0:9229 index.js
Then you need to set up Target discovery settings in the Chrome. Note that 192.168.33.11 from my sample is the static IP address providing an access to the Vargant host from the local host:

Access Vue Application on Webpack-Server in Vagrant

I set up a virtual machine with Vagrant, ubuntu xenial64, installed npm/nodejs and the vue-cli.
I scaffolded a webpack application with vue init webpack myproject. When I now run npm run devthe webpack server starts, but since it's inside the virtual machine I can't access the webpage on my PC.
I found out, that you can run webpack server with --host 0.0.0.0 but since the Vue-Cli generates the whole process, I wasn't able to figure out where I can add this parameter.
Or is there another solution?
Ok fixed it myself :). Just add this to your Vagrantfile:
config.vm.network :forwarded_port, guest: 8080, host: 80
So nothing to do with Webpack, just basic vagrant setup. This will forward the 8080 port to 80 port of your host machine. So you need to type localhost:80 in your browser to get to your application.

Vagrant port forwarding 80 to 8000 with Laravel Homestead

My Problem:
I can only access my sites through port 8000, but not 80, which makes me think it is not redirecting 80 to 8000 as it says it should be. I want to simply type local.kujif.com into my browser and it loads the site, which I read was port 80 by default. I am using curl to check it and it returns:
curl 'http://local.kujif.com'
curl: (7) Failed connect to local.kujif.com:80; No error
However if I add :8000 to the url then it works; it returns my index.php which simply prints 'test':
curl 'http://local.kujif.com:8000'
test
My Details:
I am using Laravel Homestead and Vagrant with Oracle VM VirtualBox.
In the Homestead.rb it has the port forwarding. I haven't edited it at all:
config.vm.network "forwarded_port", guest: 80, host: 8000
config.vm.network "forwarded_port", guest: 3306, host: 33060
config.vm.network "forwarded_port", guest: 5432, host: 54320
I also have Microsoft IIS installed for my work stuff. I obviously stop that service whenever I need vagrant to use the localhost.
"vagrant up" shows:
My Homestead.yaml file:
---
ip: "192.168.10.10"
memory: 2048
cpus: 1
authorize: /Users/Tyler/.ssh/id_rsa.pub
keys:
- /Users/Tyler/.ssh/id_rsa
folders:
- map: C:\DEV\Linux
to: /var/www/
sites:
- map: homestead.app
to: /home/vagrant/Code/Laravel/public
- map: local.kujif.com
to: /var/www/kujif
variables:
- key: APP_ENV
value: local
You should continue to use ports above 1024 since they are non-privileged ports, BUT if you do want you can run as port 80 on the Homestead VM, as long as you don't have anything holding on to that port on the host machine. Just tried it and it worked, with a few gotchas. First, you change that line in the .rb file from:
config.vm.network "forwarded_port", guest: 80, host: 8000
to
config.vm.network "forwarded_port", guest: 80, host: 80
When you fire your VM up after saving you will get a warning from vagrant:
==> default: You are trying to forward to privileged ports (ports <= 1024). Most
==> default: operating systems restrict this to only privileged process (typically
==> default: processes running as an administrative user). This is a warning in case
==> default: the port forwarding doesn't work. If any problems occur, please try a
==> default: port higher than 1024.
==> default: Forwarding ports...
default: 80 => 80 (adapter 1)
But it worked for me. Now, to actually get to the VM I had to use it's private IP instead of the localhost name:
http://192.168.10.10/
But sure enough my site was there and everything was working. If you decide to keep it that was you can add that IP address to your hosts file to give it a nice short name.
Hope this helps.
I see there is an accepted answer, but this alternative may also help someone.
If I understand correctly you really dislike the port "8000"!
Have you tried setting a private network?
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
/*other config stuff here */
config.vm.network :private_network, ip: "192.168.33.22"
This way you can simply use that IP address, or edit you hosts file to map the local domain to that IP.
Take a look at the Vagrant docs:Vagrant Private Networks
BTW, You shouldn't need to shutdown your IIS local server as that is running on a totally different IP range. I have Apache running locally while also accessing the VM server. This allows you to use tools like composer (to pull in laravel) on your local if needed.
I'm not sure what the confusion is - this is the way it's supposed to work.
The web server on the VM listens on port 80. Vagrant/VirtualBox forwards that port from 80 (on the VM) to 8000 (on localhost) so that you can access the site at http://localhost:8000.
Port 80 on the VM's domain name is not going to be available - that domain name probably resolves to localhost.
Try the following: dig local.kujif.com (or nslookup or even ping - I don't know what tools are available on Windows) to find out what IP address that name is resolving to. You will probably find that it's 127.0.0.1 (localhost).
You could try using the IP address set in the homestead file instead: http://192.168.10.10/ - this might work, but it will depend on how networking is configured in the VM.
Ideally, you need to set networking to "bridged" in the VM - this will make the VM look (to your network) like any other device on the network. Other networking options in the VM (sorry, I'm not familiar with the options in VirtualBox) will set the VM up with its own network that is not accessible outside the VM - this is why port forwarding is used to expose network services on the VM.
You can disable the default port forwarding completely by adding the following to the Homestead.yaml:
default_ports: false
Or configure however you like by adding something like:
ports:
- send: 80
to: 80

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