I promised a "part 2" that never was. Sorry, I am busy and/or lazy.
Now that my magic-auto-sandbox thing has evolved, it's time to revisit it.
Get virtualbox
In my case, adding repositories as instructed in https://www.virtualbox.org/wiki/Linux_Downloads.Get vagrant
It is a virtualization automation tool that was a ruby gem in its origins.Nowadays, the recommended (linux) install procedure is downloading packages for your favourite distro from: https://www.vagrantup.com/downloads.html
Create config files
Three files, read and adapt to your particular needs:./Vagrantfile
It is vagrant's config file, it tells vagrant what machine to start if it already exists or how to create it, if it hasn't been yet.Vagrant.configure("2") do |vagrant| vagrant.vm.define "project_name" do |config| # Inject code from outer FS (edit outside, run inside) # required by type: "nfs" config.vm.network "private_network", ip: '192.168.50.10' config.vm.synced_folder "./code", "/home/vagrant/code", type: "nfs" # Access app with outer browser # otherwise use rails s -b 0.0.0.0 and private ip config.vm.network "forwarded_port", guest: 3000, host: 3000 config.vm.network "public_network", bridge: 'wlan0' # http://rvm.io/integration/vagrant config.vm.provision :shell, path: 'provision/bootstrap.sh', keep_color: true config.vm.provider "virtualbox" do |vb, override| # http://www.vagrantbox.es/ # Prepare with: wget -O ../trusty-vbox.box http://goo.gl/8wqNnb override.vm.box_url = "../trusty-vbox.box" override.vm.box = "trusty-vbox" vb.name = 'project_name' vb.memory = ENV['VM_MEM'] || 1024 vb.cpus = ENV['VM_CPU'] || 2 vb.customize ['modifyvm', :id, "--natdnshostresolver1", "on"] end end end
./provision/bootstrap.sh
If you happen to be a systems person (or have one near) here is where they will suggest puppet or chef or whatever "configuration automation" tool.A simple shell script is enough for Xavi Noria, and is enough for me.
#!/usr/bin/env bash ## Ruby on Rails Development Environment Provision Script ## # Inspired by @fxn's https://github.com/rails/rails-dev-box # Configuration variables with custom values RUBY_VERSION="2.2.1" APP="project_name" HOSTNAME='project_name.dev' echo -e "\n== «$APP» on _$RUBY_VERSION_ ==\n" # Load auxiliary functions: source /vagrant/provision/functions.sh # General System layout install 'development tools' build-essential set_timezone 'Etc/UTC' setup_locale 'LANG="en_US.UTF-8"\nLANGUAGE="en_US:en LC_ALL=en_US.UTF-8"\n' hostname $HOSTNAME install Git git # Ruby & Rails: install_rvm install_postgres install 'Nokogiri dependencies' libxml2 libxml2-dev libxslt1-dev install_node # Developer happiness stuff: install 'ACK-Grep' ack-grep install 'Log colorizer' ccze install 'Vim' vim # App specific stuff install_bower echo -e "\033[1;32m All set, rock on! thanks to the awesome @fxn!\033[0m"
./provision/functions.sh
These are the parts that change less from project to project, so I have extracted them for easier reuse.#!/usr/bin/env bash echo -e "\033[1;32m Loading auxiliary functions for provision...\033[0m" # The ouput of all these installation steps is noisy. With this utility # the progress report is nice and concise. function install { echo installing $1 ... shift debian_frontend=noninteractive apt-get -y install "$@" >/dev/null 2>&1 echo -e "\033[1;32m [OK] \033[0m" } # Executes a command as the vagrant user # Example: # run 'Description' 'command' function vagrant_run { echo -e "\n$1:" eval "su -l vagrant -c '$2'" } # Installs ruby environment through RVM function install_rvm { if [ ! -x /home/vagrant/.rvm/scripts/rvm ]; then vagrant_run "Getting RVM keyring" \ 'gpg --keyserver hkp://keys.gnupg.net --recv-keys D39DC0E3' echo -e "\nInstalling RVM:" su -l vagrant -c 'curl -sSL https://get.rvm.io | bash -s -- stable' echo -e "\nLoading RVM to continue:" su -l vagrant -c 'source $HOME/.rvm/scripts/rvm' echo -e "\nInstalling Ruby ($RUBY_VERSION)" su -l vagrant -c "rvm use $RUBY_VERSION --default --install" echo -e "\nInstalling Bundler:" su -l vagrant -c 'gem install bundler' su -l vagrant -c 'echo "gem: --no-rdoc --no-ri" >> /home/vagrant/.gemrc' fi } # Installs PostgreSQL database function install_postgres { echo -e "\nInstalling Postgres DB and config..." if [ ! -x /usr/bin/psql ]; then install PostgreSQL postgresql postgresql-contrib libpq-dev sudo -u postgres createuser --superuser vagrant sudo -u postgres createdb -O vagrant ${APP}_development sudo -u postgres createdb -O vagrant ${APP}_test # enable pg_admin access from host machine: PG_CONF='/etc/postgresql/9.3/main' PUBLIC_IP=$(ip -o -4 addr show eth1 | cut -d ' ' -f 7) echo "listen_addresses = '*'" >> $PG_CONF/postgresql.conf echo "host all all $PUBLIC_IP trust" >> $PG_CONF/pg_hba.conf service postgresql restart fi } # Set VM timezone to have consistent test results function set_timezone { # http://manpages.ubuntu.com/manpages/precise/man7/debconf.7.html echo "Setting timezone to: '$1'" export DEBCONF_NONINTERACTIVE_SEEN=true DEBIAN_FRONTEND=noninteractive echo "$1" > /etc/timezone dpkg-reconfigure tzdata } function setup_locale { # Needed for docs generation. echo -e "$1" > /etc/default/locale } function install_node { install 'ExecJS runtime (for coffee)' nodejs install 'Npm' npm su -l vagrant -c 'if [ ! -f $HOME/.npmrc ]; then echo prefix = $HOME/.node >> $HOME/.npmrc echo "export PATH=\"\$PATH:\$HOME/.node/bin\"" >> $HOME/.bashrc source $HOME/.bashrc fi' if [ ! -f /usr/bin/node ]; then ln -s /usr/bin/nodejs /usr/bin/node fi } function install_bower { echo -e "\nInstalling Bower and vendored assets..." BOWER_FILE='/home/vagrant/code/.bowerrc' if [ ! -f $BOWER_FILE ]; then echo -e "{\n\t"directory": "vendor/assets/components"\n}" >> $BOWER_FILE fi if [ ! -x /home/vagrant/.node/bin/bower ]; then vagrant_run "Installing bower" "npm install -g bower --silent" # Installing bower dependencies vagrant_run "Installing bower assets" \ 'cd /home/vagrant/code; /home/vagrant/.node/bin/bower install' fi }
Get the base machine
As it is instructed in the comments on Vagrantfile:wget -O ../trusty-vbox.box http://goo.gl/8wqNnb
You will only have to do this once for all the projects you may share the base machine with. (All of them in my case)
Create the machine
You use the command:
vagrant up
and it will create (and provision) the machine the first time is called and all following occasions it will just boot it up.
To connect to your machine you use:
vagrant ssh
To stop it:
vagrant halt
To destroy (in case you are debugging your creation/provision process):
vagrant destroy
There are improvements to the experience if you set up sudo and ~/.ssh/config on the host machine so they never ask you for passwords, but I will let you decide if you want to go that path while you ponder the security implications.