One of the hardest things about getting started with Vagrant is the time it takes develop a good provisioning system for the virtual machine. Many people reach to Chef or Ansible too quickly and become overwhelmed by complexity. It was recently suggested that one start with a simple provision script.
Here is a provision script that I used recently to config a Centos 6.6 vm.
#!/bin/bash | |
# Install dependent packages | |
sudo yum update | |
sudo yum install -y apr-devel apr-util-devel autoconf automake curl-devel \ | |
g++ gcc gcc-c++ git glibc-headers httpd-devel libxml2 \ | |
libxml2-devl libxslt libxslt-devel libyaml-devel make \ | |
mysql-devel mysql-server openssl-devel patch readline \ | |
readline-devel zlib zlib-devel | |
if ! [ -d /home/vagrant/.rbenv ]; then | |
echo "Installing rbenv" | |
git clone git://github.com/sstephenson/rbenv.git ~/.rbenv | |
git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build | |
echo "export PATH=\$HOME/.rbenv/bin:\$PATH" >> /home/vagrant/.bash_profile | |
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile | |
source ~/.bash_profile | |
rbenv install 2.2.2 | |
rbenv rehash | |
rbenv global 2.2.2 | |
gem update --system | |
gem install bundler | |
fi | |
echo "Gem home is $GEM_HOME" | |
echo "Path is $PATH" | |
MYSQL_RUNNING=$(service mysqld status | egrep "mysql.*running" | wc -l) | |
if [ "$MYSQL_RUNNING" -ne 1 ]; then | |
echo 'Starting Mysql' | |
sudo /sbin/service mysqld start | |
sudo /sbin/chkconfig mysqld on | |
fi | |
DATABASE_YML="/vagrant/config/database.yml" | |
APP_DB_USERNAME="blog_user" | |
APP_DB_PASSWORD="blog_user91x91x" | |
if [ -f $DATABASE_YML ]; | |
then | |
echo "File $DATABASE_YML exists." | |
else | |
echo "File $DATABASE_YML does not exist, creating." | |
read -r -d '' CREATE_USER_SQL <<_EOF_ | |
CREATE USER '$APP_DB_USERNAME'@'localhost' IDENTIFIED BY '$APP_DB_PASSWORD'; | |
CREATE USER '$APP_DB_USERNAME'@'%' IDENTIFIED BY '$APP_DB_PASSWORD'; | |
GRANT ALL PRIVILEGES ON *.* TO '$APP_DB_USERNAME'@'localhost' WITH GRANT OPTION; | |
GRANT ALL PRIVILEGES ON *.* TO '$APP_DB_USERNAME'@'%' WITH GRANT OPTION; | |
_EOF_ | |
echo "Creating mysql user:" | |
echo $CREATE_USER_SQL | |
mysql -uroot -e "$CREATE_USER_SQL" | |
cat > $DATABASE_YML <<_EOF_ | |
default: &default | |
adapter: mysql2 | |
encoding: utf8 | |
reconnect: false | |
pool: 5 | |
username: $APP_DB_USERNAME | |
password: $APP_DB_PASSWORD | |
host: localhost | |
development: | |
<<: *default | |
database: blog_development | |
test: | |
<<: *default | |
database: blog_test | |
production: | |
<<: *default | |
database: blog_production | |
_EOF_ | |
fi | |
echo "Installing gems" | |
cd /vagrant | |
bundle install | |
bundle exec rake db:create:all --trace | |
bundle exec rake db:migrate --trace |
Here is the Vagrantfile:
# Host => Guest (VM) | |
FORWARD_PORTS = { | |
3000 => 3000, # webrick | |
13_306 => 3306 # MySQL | |
} | |
# All Vagrant configuration is done below. The "2" in Vagrant.configure | |
# configures the configuration version (we support older styles for | |
# backwards compatibility). Please don't change it unless you know what | |
# you're doing. | |
Vagrant.configure(2) do |config| | |
config.vm.box = 'opscode_centos-6.6' | |
config.vm.provider :virtualbox do |_f, override| | |
override.vm.box_url = 'https://s3.amazonaws.com/centos-vagrant/opscode_centos-6.6_chef-provisionerless.box' | |
end | |
config.ssh.password = 'vagrant' | |
config.vm.provision :shell, path: 'provision.sh', privileged: false | |
config.vm.synced_folder( | |
'.', | |
'/vagrant', | |
type: 'rsync', | |
rsync__exclude: [ | |
'.git/', | |
'.vagrant/', | |
'config/database.yml', | |
'log/*', | |
'tmp/' | |
] | |
) | |
FORWARD_PORTS.each do |host, guest| | |
config.vm.network :forwarded_port, host: host, guest: guest | |
end | |
end |
You will notice in the Vagrantfile that we forward the MySQL port 3306 to 13306. I still want to connect to the MySQL database on the vm from my local machine so to this I update the my local database.yml.
default: &default | |
adapter: mysql2 | |
encoding: utf8 | |
reconnect: false | |
pool: 5 | |
port: 13306 | |
username: blog_user | |
password: blog_user91x91x | |
host: localhost | |
development: | |
<<: *default | |
database: blog_development | |
test: | |
<<: *default | |
database: blog_test | |
production: | |
<<: *default | |
database: blog_production |
I can now run commands like bundle exec rake db:migrate
on my local machine. Since it can modify files, this is preferred. I run the server as well my rspecs on the vagrant box. During development, I have an rsync command running as follows to sync my file changes down to the local machine.
vagrant rsync-auto
Next time, I can show how this same setup can be done with PostgreSQL.