How to access Guest's port 3000 from Host? - ruby-on-rails

Here's my Vagrantfile:
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure(2) do |config|
config.vm.box = "ubuntu-14.04-x64"
# Sync'd folders
config.vm.synced_folder ".", "/vagrant", disabled: true
config.vm.synced_folder "~/work", "/home/vagrant/work", create: true
config.vm.synced_folder "~/apt-archives", "/var/cache/apt/archives/", create: true
# Ubuntu VM
config.vm.define "ubuntu" do |ubuntu|
ubuntu.vm.provision "shell", path: "provision.sh", privileged: false
ubuntu.vm.network "forwarded_port", guest: 3000, host: 8080 # http
ubuntu.vm.network "private_network", ip: "10.20.30.100"
ubuntu.vm.hostname = "ubuntu"
# VirtualBox Specific Stuff
# https://www.virtualbox.org/manual/ch08.html
config.vm.provider "virtualbox" do |vb|
# Set more RAM
vb.customize ["modifyvm", :id, "--memory", "2048"]
# More CPU Cores
vb.customize ["modifyvm", :id, "--cpus", "2"]
end # End config.vm.provider virtualbox
end # End config.vm.define ubuntu
end
For example, when I run rails app using port 3000, from the guest machine I would accessing http://localhost:3000.
But I'm trying to access the app via host's browser.
None of below worked:
http://10.20.30.100:8080
https://10.20.30.100:8080
http://10.20.30.100:3000
https://10.20.30.100:3000
Browser on the host's showing: ERR_CONNECTION_REFUSED

For security reasons, Rails 4.2 limits remote access while in development mode. This is done by binding the server to 'localhost' rather than '0.0.0.0' ....
To access Rails working on a VM (such as one created by Vagrant), you need to change the default Rails IP binding back to '0.0.0.0'.
See the answers on the following StackOverflow Question, there are a number of different approaches suggested.
The idea is to get Rails running either by forcing the following command:
rails s -b 0.0.0.0
Or by hardcoding the binding into the Rails app (which I found less desirable):
# add this to config/boot.rb
require 'rails/commands/server'
module Rails
class Server
def default_options
super.merge(Host: '0.0.0.0')
end
end
end
Personally, I would have probably gone with the suggestion to use foreman and a Procfile:
# Procfile in Rails application root
web: bundle exec rails s -b 0.0.0.0
This would allow, I believe, for better easier deployment synchronicity.

Related

Connecting two vagrant machines

I am currently attempting to connect two vagrant environments. One is a web application with an associated postgres database. The other is an API application which makes calls to the postgres database on the first vagrant machine. Can anyone provide advice as to how this can be achieved. I believe I will need to change my database.yml or envirornment.rb file but not quite sure how. My vagrantfiles and database.yml files are currently like so:
Front-End Machine Vagrantfile:
Vagrant.configure("2") do |config|
config.vm.box = "hashicorp/precise64"
config.vm.network "forwarded_port", guest: 3000, host: 3000
config.vm.synced_folder "../Base", "/Base"
config.vm.synced_folder "../api", "/API"
end
Front-End Machine database.yml:
default: &default
adapter: postgresql
database: chsh
development: &development
<<: *default
host: localhost
username: username
password: password
database: database_name
pool: 10
API Machine:
Vagrant.configure("2") do |config|
config.vm.box = "hashicorp/precise64"
config.vm.network "forwarded_port", guest: 3002, host: 3002
config.vm.synced_folder "../Base", "/Base"
config.vm.provider "virtualbox" do |vb|
vb.gui = true
end
end
As I read the code, I didn't see any way to configure multiple machines.
You can bypass this by reconfiguring before use..
module Vagrant
def set(name)
send(name) if respond_to?(name)
end
def front_end
Vagrant.configure("2") do |config|
config.vm.box = "hashicorp/precise64"
config.vm.network "forwarded_port", guest: 3000, host: 3000
config.vm.synced_folder "../Base", "/Base"
config.vm.synced_folder "../api", "/API"
end
end
def api
Vagrant.configure("2") do |config|
config.vm.box = "hashicorp/precise64"
config.vm.network "forwarded_port", guest: 3002, host: 3002
config.vm.synced_folder "../Base", "/Base"
config.vm.provider "virtualbox" do |vb|
vb.gui = true
end
end
end
end
You will be then able to do something like this:
Vagrant.set(:front_end)
Vagrant.set(:api)

Building a Redis cluster using docker images on top of Vagrant: Cannot ping machines

I'm trying to build a simple redis cluster locally on OSX, using docker inside virtualbox VMS. Specifically, I want to create a master redis node (192.168.0.100) with two slaves (.101 and .102). This involves configuring each machine and issuing a command to each slave to tell it who the master is in the key-value-store relationship.
This worked great, until I decided to make my configuration more flexible by doing some programmatic stuff inside my Vagrantfile. The result is that I am unable to even ping any of the machines beside .102, let alone uses redis-cli commands (for example, redis-cli -h 192.168.0.100 INFO to see that the master has slaves set up correctly)
My goals/constraints:
Run docker inside a virtualbox VM: I saw several ways to do this when reading the docs. I chose the way I do it because I don't want to refer to a ton of external files.
Run a sequence of commands on each VM after configuration to set slaves and whatnot.
I'd prefer not to just use boot2docker as I have a bunch other stuff I'm gonna be adding... twemproxy, sentinel and I want to simulate a production environment at least a little bit.
What am I doing wrong in my new file?
EDIT: I've investigated a bit more. One thing I tried was destroying all images, then running the old vagrant file to build the machines, and then reloading them with the new vagrant file. In this scenario, the machines worked, though each time I'd see authentication failure messages like redis1: Warning: Authentication failure. Retrying... after the machine had gone up. I was able to ping the machine no problem though.
New Vagrantfile (uses config file below):
require './config.rb'
include RedisClusterConfig
Vagrant.configure(2) do |config|
config.vm.provider "virtualbox"
## Redis Nodes (Can define multiple triplets) ##
for node in RedisClusterConfig.redisNodes
config.vm.define node.name do |a|
a.vm.hostname = node.name
a.vm.box = "ubuntu/trusty64"
# Skip checking for an updated Vagrant box
a.vm.box_check_update = false
# Networking
a.vm.network :private_network, ip: node.address
a.ssh.forward_agent = true
a.ssh.insert_key = false
# Set up docker with 'redis' image
a.vm.provision "docker" do |d|
d.images = ["redis"]
d.run "redis", name: "redis", args: "-p "+node.port+":"+node.port
end
# Additional configuration
a.trigger.after [:up, :resume, :reload, :provision] do
# Master/slave
unless node.slaveOfAddress.nil?
system("redis-cli -h " + node.address + " SLAVEOF " + node.slaveOfAddress + " " + node.slaveOfPort)
puts "Finished setting up slave node: " + node.name
else
puts "Finished setting up master node: " + node.name
end
end
end
end
end
config.rb:
module RedisClusterConfig
attr_reader :redisNodes
RedisNode = Struct.new("RedisNode", :name, :address, :port, :slaveOfAddress, :slaveOfPort)
p = "6379" # Default redis port
baseAddr = "192.168.0."
# Define a triplet
redis0 = RedisNode.new("redis0", baseAddr + "100", p, nil, nil)
redis1 = RedisNode.new("redis1", baseAddr + "101", p, baseAddr + "100", p)
redis2 = RedisNode.new("redis2", baseAddr + "102", p, baseAddr + "100", p)
#redisNodes = [redis0, redis1, redis2]
end
Old Vagrantfile:
# Make sure you have triggers plugin:
# vagrant plugin install vagrant-triggers
#
# TODO:
# - We really would like to run some shell commands after everything is done, not after each machine is provisioned
Vagrant.configure(2) do |config|
config.vm.provider "virtualbox"
## Redis Nodes ##
### Master Node###
config.vm.define "redis0" do |a|
a.vm.hostname = "redis0"
a.vm.box = "ubuntu/trusty64"
# Skip checking for an updated Vagrant box
a.vm.box_check_update = false
# Networking
a.vm.network :private_network, ip: "192.168.0.100"
a.ssh.forward_agent = true
a.ssh.insert_key = false
a.vm.provision "docker" do |d|
d.images = ["redis"]
d.run "redis",
name: "redis",
args: "-p 6379:6379"
end
end
### Slave Nodes ###
config.vm.define "redis1" do |a|
a.vm.hostname = "redis1"
a.vm.box = "ubuntu/trusty64"
# Skip checking for an updated Vagrant box
a.vm.box_check_update = false
# Networking
a.vm.network :private_network, ip: "192.168.0.101"
a.ssh.forward_agent = true
a.ssh.insert_key = false
a.vm.provision "docker" do |d|
d.images = ["redis"]
d.run "redis",
name: "redis",
args: "-p 6379:6379"
end
end
config.vm.define "redis2" do |a|
a.vm.hostname = "redis2"
a.vm.box = "ubuntu/trusty64"
# Skip checking for an updated Vagrant box
a.vm.box_check_update = false
# Networking
a.vm.network :private_network, ip: "192.168.0.102"
a.ssh.forward_agent = true
a.ssh.insert_key = false
a.vm.provision "docker" do |d|
d.images = ["redis"]
d.run "redis",
name: "redis",
args: "-p 6379:6379"
end
end
# After everything else has finished provisioning...
config.trigger.after [:up, :resume, :reload] do
# Configuring redis master/slave triplet
system('echo Configuring redis master/slave triplet...')
system('redis-cli -h 192.168.0.101 SLAVEOF 192.168.0.100 6379')
system('redis-cli -h 192.168.0.102 SLAVEOF 192.168.0.100 6379')
end
end

Vagrant-env plugin throwing error - line "VAR_NAME=var_value" doesn't match format

I have ruby 2.1.5 installed on Ubuntu with Vagrant 1.7
I ran:
~$ vagrant plugin install vagrant-env
as described at gosuri/vagrant-env.
I should also mention that this now only works when I add:
require 'dotenv'
Dotenv.load
which the doc (README) does not specify to implement into the Vagrantfile. If I leave this out then I get an error saying that the line with:
config.env.enable
is an unknown configuration section.
I have my .env file in the same directory as Vagrantfile. No matter what I have in the file, it errors on the first line. I can leave it blank or make it a comment and it will still say the first line is incorrect format.
I am wanting to use this because it is the only solution I can find that will allow me to pass ENV variables to the Vagrant file as well as the manifest files Puppet.
Here is a snippet of my Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :
require 'dotenv'
Dotenv.load
Vagrant.configure("2") do |config|
config.env.enable
#config.dotenv.enabled = true
config.vm.provider "virtualbox" do |vb|
vb.customize ["modifyvm", :id, "--memory", "#{ENV['MEMORY_ALLOCATION']}"]
end
config.vm.network "public_network", ip: ENV['PUBLIC_IP']
end
Vagrant::Config.run do |config|
...
config.vm.define "devboxserver" do |app|
...
app.vm.provision :puppet do |puppet|
puppet.facter = {
"env" => ENV
}
puppet.module_path = "puppet/modules"
puppet.manifests_path = "puppet/manifests"
puppet.manifest_file = "site.pp"
puppet.options="--verbose --debug"
end
end
end
As you can see, I also tried vagrant-dotenv (which you see is commented out) but that was also causing me problems as it was trying to call on config variables before the Vagrantfile was even loaded. But I guess that is another issue. I had to remove that gem from the .vagrant.d directory.
But getting back to the vagrant-env issue, I wrote my .env file as with what I could tell from the github plugin site and the referenced article
USER_NAME=jason
PUBLIC_IP=192.168.1.00
MEMORY_ALLOCATION=1024
GITREPO_ACCOUNT_URL=https://github.com/me
GITREPO_URL=https://github.com/me/my_app
POSTGRES_PASSWORD=secret-pass
DEV_DB_NAME=my_app_development
PROD_DB_NAME=my_app_production
TEST_DB_NAME=my_app_test
And the error I get is:
jason#host:~/folder/vagrant$ vagrant up
There is a syntax error in the following Vagrantfile. The syntax error
message is reproduced below for convenience:
Line "USER_NAME=jason" doesn't match format
Since the goal is to create environmental variables throughout my vagrant execution and share with Puppet, I did what any sane rubyist (or programmer) would do. I created my own simple hack by grabbing the .env variables and turning them into a hash.
I added this hack to the top of my Vagrant file:
# -*- mode: ruby -*-
# vi: set ft=ruby :
env = {}
File.read(".env").split("\n").each do |ef|
env[ef.split("=")[0]] = ef.split("=")[1]
end
Vagrant.configure("2") do |config|
config.vm.provider "virtualbox" do |vb|
vb.customize ["modifyvm", :id, "--memory", env['MEMORY_ALLOCATION']]
end
config.vm.network "public_network", ip: env['PUBLIC_IP']
end
...
However, since the Puppet files aren't really ruby files, using puppet.facter to grab to set the "env" variable ($env) to a hash does not work since we are talking about two different language constructs.
Instead, I just extended the puppet.facter list and instead of one $env hash I now have a puppet.facter variable set for all the .env variables.
...
app.vm.provision :puppet do |puppet|
puppet.facter = {
"fqdn" => "#{env['BOX_NAME']}.local",
"user_name" => env['USER_NAME'],
"box_name" => env['BOX_NAME'],
"gitrepo_account_url" => env['GITREPO_ACCOUNT_URL'],
"gitrepo_url" => env['GITREPO_URL'],
"postgres_password" => env['POSTGRES_PASSWORD'],
"dev_db_name" => env['DEV_DB_NAME'],
"prod_db_name" => env['PROD_DB_NAME'],
"test_db_name" => env['TEST_DB_NAME'],
"my_email" => env['MY_EMAIL']
}
puppet.module_path = "puppet/modules"
puppet.manifests_path = "puppet/manifests"
puppet.manifest_file = "site.pp"
puppet.options="--verbose --debug"
end
...
In my puppet scripts I just call variables like normal. EX: $user_name, $dev_db_name, etc.
I then removed vagrant-env as it is no longer needed.

Vagrant + Rails not showing page in local machine browser

vagrant#precise32:/vagrant$ rails s
=> Booting WEBrick
=> Rails 4.1.0 application starting in development on http://0.0.0.0:3000
=> Run `rails server -h` for more startup options
=> Notice: server is listening on all interfaces (0.0.0.0). Consider using 127.0.0.1 (--binding option)
=> Ctrl-C to shutdown server
[2014-08-24 23:33:39] INFO WEBrick 1.3.1
[2014-08-24 23:33:39] INFO ruby 2.1.2 (2014-05-08) [i686-linux]
[2014-08-24 23:33:39] INFO WEBrick::HTTPServer#start: pid=18812 port=3000
In chrome I'm getting the "This webpage is not available" error.
I follow this tutorial to setup Vagrant with Rails - http://tutorials.jumpstartlab.com/topics/vagrant_setup.html
What could be wrong here?
Edit:
Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
# All Vagrant configuration is done here. The most common configuration
# options are documented and commented below. For a complete reference,
# please see the online documentation at vagrantup.com.
# Every Vagrant virtual environment requires a box to build off of.
config.vm.box = "hashicorp/precise32"
# Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs
# `vagrant box outdated`. This is not recommended.
# config.vm.box_check_update = false
# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine. In the example below,
# accessing "localhost:8080" will access port 80 on the guest machine.
config.vm.network "forwarded_port", guest: 80, host: 3000
# Create a private network, which allows host-only access to the machine
# using a specific IP.
# config.vm.network "private_network", ip: "192.168.33.10"
# Create a public network, which generally matched to bridged network.
# Bridged networks make the machine appear as another physical device on
# your network.
# config.vm.network "public_network"
# If true, then any SSH connections made will enable agent forwarding.
# Default value: false
# config.ssh.forward_agent = true
# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
# argument is a set of non-required options.
# config.vm.synced_folder "../data", "/vagrant_data"
# Provider-specific configuration so you can fine-tune various
# backing providers for Vagrant. These expose provider-specific options.
# Example for VirtualBox:
#
# config.vm.provider "virtualbox" do |vb|
# # Don't boot with headless mode
# vb.gui = true
#
# # Use VBoxManage to customize the VM. For example to change memory:
# vb.customize ["modifyvm", :id, "--memory", "1024"]
# end
#
# View the documentation for the provider you're using for more
# information on available options.
# Enable provisioning with CFEngine. CFEngine Community packages are
# automatically installed. For example, configure the host as a
# policy server and optionally a policy file to run:
#
# config.vm.provision "cfengine" do |cf|
# cf.am_policy_hub = true
# # cf.run_file = "motd.cf"
# end
#
# You can also configure and bootstrap a client to an existing
# policy server:
#
# config.vm.provision "cfengine" do |cf|
# cf.policy_server_address = "10.0.2.15"
# end
# Enable provisioning with Puppet stand alone. Puppet manifests
# are contained in a directory path relative to this Vagrantfile.
# You will need to create the manifests directory and a manifest in
# the file default.pp in the manifests_path directory.
#
# config.vm.provision "puppet" do |puppet|
# puppet.manifests_path = "manifests"
# puppet.manifest_file = "site.pp"
# end
# Enable provisioning with chef solo, specifying a cookbooks path, roles
# path, and data_bags path (all relative to this Vagrantfile), and adding
# some recipes and/or roles.
#
# config.vm.provision "chef_solo" do |chef|
# chef.cookbooks_path = "../my-recipes/cookbooks"
# chef.roles_path = "../my-recipes/roles"
# chef.data_bags_path = "../my-recipes/data_bags"
# chef.add_recipe "mysql"
# chef.add_role "web"
#
# # You may also specify custom JSON attributes:
# chef.json = { mysql_password: "foo" }
# end
# Enable provisioning with chef server, specifying the chef server URL,
# and the path to the validation key (relative to this Vagrantfile).
#
# The Opscode Platform uses HTTPS. Substitute your organization for
# ORGNAME in the URL and validation key.
#
# If you have your own Chef Server, use the appropriate URL, which may be
# HTTP instead of HTTPS depending on your configuration. Also change the
# validation key to validation.pem.
#
# config.vm.provision "chef_client" do |chef|
# chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME"
# chef.validation_key_path = "ORGNAME-validator.pem"
# end
#
# If you're using the Opscode platform, your validator client is
# ORGNAME-validator, replacing ORGNAME with your organization name.
#
# If you have your own Chef Server, the default validation client name is
# chef-validator, unless you changed the configuration.
#
# chef.validation_client_name = "ORGNAME-validator"
end
Post your Vagrantfile, but you're probably missing the port forwarding configuration for port 3000.
Update: not missing, just wrong. Change both port options to 3000 and you should be good.

Port management strategy for Vagrant on Windows?

I was wondering if there is a community accepted pattern for managing vagrant port mappings? Auto correction is great, but it doesn't help with integration testing. In my case, I spin up multiple boxes, provision with Chef, and then run Serverspec.
You can see below, that with auto port assignments, the rake config file is no longer predictable when multiple boxes are used. Before I start another Yak shaving project, I was wondering how others handle this situation?
Vagrant.configure("2") do |config|
config.vm.define 'wsus_server',primary: true do |config|
config.vm.network "forwarded_port", guest: 5985, host: 15985, auto_correct: true
config.vm.network "forwarded_port", guest: 3389, host: 13390, auto_correct: true
config.vm.network "forwarded_port", guest: 4000, host: 4000, auto_correct: true
end
config.vm.define 'wsus_client' do |config|
config.vm.network "forwarded_port", guest: 5985, host: 15985, auto_correct: true
config.vm.network "forwarded_port", guest: 3389, host: 13390, auto_correct: true
config.vm.network "forwarded_port", guest: 4000, host: 4000, auto_correct: true
end
end
serverspec (rake config):
require 'serverspec'
require 'winrm'
include Serverspec::Helper::WinRM
include Serverspec::Helper::Windows
RSpec.configure do |c|
user = 'vagrant'
pass = 'vagrant'
endpoint = "http://localhost:15985/wsman"
c.winrm = ::WinRM::WinRMWebService.new(endpoint, :ssl, :user => user, :pass => pass, :basic_auth_only => true)
c.winrm.set_timeout 300 # 5 minutes max timeout for any operation
end
I think the community accepted pattern for that these days is to use Test Kitchen instead of firing up individual VMs in Vagrant.
You can even use use the kitchen-docker driver to avoid firing up VMs at all. If you're on OS X or Windows, dvm can help with creating a docker-server VM seamlessly for that.
You can also have a look at meez to get you started with that. I've written an article on InfoQ about that if you're interested.

Resources