On Github bertvv / vagrant-presentation
Bert Van Vreckem
$ vagrant --version Vagrant 1.7.4 $ VBoxHeadless --version Oracle VM VirtualBox Headless Interface 4.3.30 (C) 2008-2015 Oracle Corporation All rights reserved. 4.3.30_RPMFusionr10610 $ ifconfig vboxnet0 => 192.168.56.1
(sorry, the code is no longer up-to-date)
$ vagrant init centos/7 $ vagrant up $ vagrant ssh
$ vagrant init centos/7 A `Vagrantfile` has been placed in this directory. You are now ready to `vagrant up` your first virtual environment! Please read the comments in the Vagrantfile as well as documentation on `vagrantup.com` for more information on using Vagrant.
A Vagrantfile is created (that's all!)
$ vagrant up Bringing machine 'default' up with 'virtualbox' provider... ==> default: Box 'centos/7' could not be found. Attempting to find and install... default: Box Provider: virtualbox default: Box Version: >= 0 ==> default: Loading metadata for box 'centos/7' default: URL: https://atlas.hashicorp.com/centos/7 ==> default: Adding box 'centos/7' (v1505.01) for provider: virtualbox default: Downloading: https://atlas.hashicorp.com/centos/boxes/7/versions/1505.01/providers/virtualbox.box ==> default: Box download is resuming from prior download progress ==> default: Successfully added box 'centos/7' (v1505.01) for 'virtualbox'! ==> default: Importing base box 'centos/7'... ==> default: Matching MAC address for NAT networking... ==> default: Checking if box 'centos/7' is up to date... ==> default: Setting the name of the VM: test_default_1441636487571_53914 ==> default: Fixed port collision for 22 => 2222. Now on port 2200. ==> default: Clearing any previously set network interfaces... ==> default: Preparing network interfaces based on configuration... default: Adapter 1: nat
==> default: Forwarding ports... default: 22 => 2200 (adapter 1) ==> default: Booting VM... ==> default: Waiting for machine to boot. This may take a few minutes... default: SSH address: 127.0.0.1:2200 default: SSH username: vagrant default: SSH auth method: private key default: Warning: Connection timeout. Retrying... default: default: Vagrant insecure key detected. Vagrant will automatically replace default: this with a newly generated keypair for better security. default: default: Inserting generated public key within guest... default: Removing insecure key from the guest if it's present... default: Key inserted! Disconnecting and reconnecting using new SSH key... ==> default: Machine booted and ready! ==> default: Checking for guest additions in VM...
default: No guest additions were detected on the base box for this VM! Guest default: additions are required for forwarded ports, shared folders, host only default: networking, and more. If SSH fails on this machine, please install default: the guest additions and repackage the box to continue. default: default: This is not an error message; everything may continue to work properly, default: in which case you may ignore this message. ==> default: Installing rsync to the VM... ==> default: Rsyncing folder: /home/bert/Downloads/test/ => /home/vagrant/sync
$ vagrant up
You now have a working VM, ready for use:
$ vagrant ssh [vagrant@localhost ~]$ cat /etc/redhat-release CentOS Linux release 7.1.1503 (Core) [vagrant@localhost ~]$
Minimal Vagrantfile:
VAGRANTFILE_API_VERSION = '2' Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = 'centos/7' end
Vagrantfile = Ruby
From the command line (Published on Atlas):
$ vagrant box add centos/7 $ vagrant init centos/7
From the command line (Box not on Atlas):
$ vagrant box add --name centos71-nocm \ https://tinfbo2.hogent.be/pub/vm/centos71-nocm-1.0.16.box $ vagrant init centos71-nocm
In your Vagrantfile (only applies to "old" style):
VAGRANTFILE_API_VERSION = '2' Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = 'centos71-nocm' config.vm.box_url = 'https://tinfbo2.hogent.be/pub/vm/centos71-nocm-1.0.16.box' end
$ vagrant destroy default: Are you sure you want to destroy the 'default' VM? [y/N] y ==> default: Forcing shutdown of VM... ==> default: Destroying VM and associated drives... $ vagrant up [...] $ vagrant ssh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
VAGRANTFILE_API_VERSION = '2' HOST_NAME = 'box001' Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.hostname = HOST_NAME config.vm.box = 'centos/7' config.vm.network :private_network, ip: '192.168.56.65', netmask: '255.255.255.0' config.vm.provider :virtualbox do |vb| vb.name = HOST_NAME vb.customize ['modifyvm', :id, '--memory', 256] end end
For more info,
When you change the Vagrantfile, do:
$ vagrant reload
Or, if the change is profound:
$ vagrant destroy -f $ vagrant up
Vagrantfile:
config.vm.define HOST_NAME do |node| node.vm.hostname = HOST_NAME [...] end
Specify HOST_NAME after vagrant command:
$ vagrant status # Status of *all* boxes $ vagrant up box001 # Boot box001 $ vagrant up # Boot *all* defined boxes $ vagrant ssh box001
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
VAGRANTFILE_API_VERSION = '2' Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.define 'box001' do |node| node.vm.hostname = 'box001' node.vm.box = 'centos/7' node.vm.network :private_network, ip: '192.168.56.65', netmask: '255.255.255.0' node.vm.provider :virtualbox do |vb| vb.name = 'box001' end end
16 17 18 19 20 21 22 23 24 25 26 27
config.vm.define 'box002' do |node| node.vm.hostname = 'box002' node.vm.box = 'centos/7' node.vm.network :private_network, ip: '192.168.56.66', netmask: '255.255.255.0' node.vm.provider :virtualbox do |vb| vb.name = 'box002' end end end
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
hosts = [ { name: 'box001', ip: '192.168.56.65' }, { name: 'box002', ip: '192.168.56.66' }] Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| hosts.each do |host| config.vm.define host[:name] do |node| node.vm.hostname = host[:name] node.vm.box = 'centos/7' node.vm.network :private_network, ip: host[:ip], netmask: '255.255.255.0' node.vm.provider :virtualbox do |vb| vb.name = host[:name] end end end end
$ vagrant init user/box # Create Vagrantfile for specified base box $ vim Vagrantfile # Customize your box $ vagrant up [host] # Create VM(s) if needed and boot $ vagrant reload [host] # After every change to Vagrantfile $ vagrant halt [host] # Poweroff $ vagrant destroy [host] # Clean up! $ vagrant ssh [host] # log in $ vagrant status [host] # Status of your VM(s)
= From Just Enough Operating System to fully functional configured box
Add to your Vagrantfile
config.vm.provision 'shell', path: 'provision.sh'
Put the script into the same folder as Vagrantfile
Installs Apache and PHP
#!/bin/bash -eu # provision.sh -- Install Apache and a test PHP script sudo rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6 yum install -y httpd php service httpd start chkconfig httpd on cat > /var/www/html/index.php << EOF <?php phpinfo(); ?> EOF
MySQL is left as an exercise for the reader ;-)
Add to your Vagrantfile:
config.vm.synced_folder 'html', '/var/www/html'
Create folder html in your project root
$ tree . |-- html | `-- index.php |-- provision.sh `-- Vagrantfile
Vagrant reload
(of course, you know this, you went to the talks yesterday...)
config.vm.define 'box001' do |node| [...] node.vm.provisioning 'ansible' do |ansible| ansible.playbook = 'ansible/site.yml' end end
Pro tips:
First, on one box
Then, database on a separate machine
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
VAGRANTFILE_API_VERSION = '2' hosts = [ { name: 'box001', ip: '192.168.56.65' }, { name: 'box002', ip: '192.168.56.66' } ] Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = 'centos/7' hosts.each do |host| config.vm.define host[:name] do |node| node.vm.hostname = host[:name] node.vm.network :private_network, ip: host[:ip], netmask: '255.255.255.0' node.vm.synced_folder 'html', '/var/www/html' node.vm.provider :virtualbox do |vb| vb.name = host[:name] end node.vm.provision 'ansible' do |ansible| ansible.playbook = 'ansible/site.yml' end end end end
$ tree ansible/ ansible/ |-- group_vars | `-- all |-- roles | |-- common | | `-- tasks | | `-- main.yml | |-- db | | `-- tasks | | `-- main.yml | `-- web | `-- tasks | `-- main.yml `-- site.yml
--- - hosts: box001 sudo: true roles: - common - web - db
--- # file common/tasks/main.yml - name: Install base packages yum: pkg={{item}} state=installed with_items: - libselinux-python
--- # file web/tasks/main.yml - name: Install Apache yum: pkg={{item}} state=installed with_items: - httpd - php - php-xml - php-mysql - name: Start Apache service service: name=httpd state=running enabled=yes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
--- # file db/tasks/main.yml - name: Install MySQL yum: pkg={{item}} state=installed with_items: - mysql - mysql-server - MySQL-python - name: Start MySQL service service: name=mysqld state=running enabled=yes - name: Create application database mysql_db: name={{ dbname }} state=present - name: Create application database user mysql_user: name={{ dbuser }} password={{ dbpasswd }} priv=*.*:ALL host='localhost' state=present
--- # file group_vars/all # Application database dbname: appdb dbuser: appusr dbpasswd: CaxWeikun6
E.g. Mediawiki
Unpack latest mediawiki.tar.gz into html/wiki/ directory Surf to http://192.168.56.65/wiki and follow instructions Enter values from group_vars/all in the install page Download LocalSite.php and save in html/wiki/Automating Mediawiki installation is left as an exercise to the reader... ;-)
Inventory file, automatically created by Vagrant:
$ cat .vagrant/provisioners/ansible/inventory/vagrant_ansible_inventory # Generated by Vagrant box001 ansible_ssh_host=127.0.0.1 ansible_ssh_port=2222 box002 ansible_ssh_host=127.0.0.1 ansible_ssh_port=2200
In production, just use a different inventory file!
What should change?
--- # file site.yml - hosts: box001 sudo: true roles: - common - web - hosts: box002 sudo: true roles: - common - db
What should change?
--- # db/tasks/main.yml [...] - name: Create application database user mysql_user: name={{ dbuser }} password={{ dbpasswd }} priv=*.*:ALL host='%' state=present
This should be easy to automate
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
# Enable provisioning with chef solo config.vm.provision :chef_solo do |chef| chef.cookbooks_path = "cookbooks" chef.add_recipe "yum" chef.add_recipe "yum::epel" chef.add_recipe "openssl" chef.add_recipe "apache2" chef.add_recipe "apache2::default" chef.add_recipe "apache2::mod_ssl" chef.add_recipe "mysql" chef.add_recipe "mysql::server" chef.add_recipe "php" chef.add_recipe "php::module_apc" chef.add_recipe "php::module_curl" chef.add_recipe "php::module_mysql" chef.add_recipe "apache2::mod_php5" chef.add_recipe "apache2::mod_rewrite" chef.json = { :mysql => { :server_root_password => 'root', :bind_address => '127.0.0.1' } } end
See https://github.com/bertvv/ansible-skeleton
- name: srv001 ip: 192.168.56.10 - name: srv002 box: fedora22-nocm box_url: https://tinfbo2.hogent.be/pub/vm/fedora22-nocm-1.0.15.box synced_folders: - src: test dest: /tmp/test - src: www dest: /var/www/html options: :create: true :owner: root :group: root :mount_options: ['dmode=0755', 'fmode=0644']
Sometimes, the available base boxes just aren't good enough...
Packer is a tool for creating identical machine images for multiple platforms from a single source configuration.
Presentation slides: https://github.com/bertvv/vagrant-presentation
Code (not up-to-date): https://github.com/bertvv/vagrant-example
More at:
https://github.com/bertvv/ https://www.youtube.com/user/bertvvrhogent/
CC-BY