====== Технология Vagrant ====== * [[https://ru.wikipedia.org/wiki/Vagrant|HashiCorp Vagrant]] * [[https://www.vagrantup.com/|Vagrant - Development Environments Made Easy]] * [[https://learn.hashicorp.com/tutorials/vagrant/getting-started-index|Quick Start]] * [[https://app.vagrantup.com/boxes/search|Discover Vagrant Boxes]] * [[https://oracle-base.com/articles/vm/create-a-vagrant-base-box-virtualbox|Create a Vagrant Base Box (VirtualBox)]] ===== Установка ===== * [[https://hashicorp-releases.yandexcloud.net/vagrant/]] * [[https://val.bmstu.ru/unix/HashiCorp/vagrant_2.4.1_windows_amd64.msi]] * Можно не перезагружать систему, но нужно перезапустить Cmder ===== Подготовка командной строки ===== ==== Cmder ==== * [[Cmder]] λ bash λ cd ===== Управление образами ===== * [[https://oracle-base.com/articles/vm/create-a-vagrant-base-box-virtualbox|Create a Vagrant Base Box (VirtualBox)]] + [[https://bbs.archlinux.org/viewtopic.php?id=270005|[SOLVED] Latest sshd not accepting key algorithms]] * [[https://vagrantcloud.com/debian/bullseye64]] * [[https://val.bmstu.ru/unix/HashiCorp/ubuntu_20.04.box]] * [[https://val.bmstu.ru/unix/HashiCorp/debian12-generic.box]] * [[Переменные окружения]] * [[https://stackoverflow.com/questions/19872591/how-to-use-vagrant-in-a-proxy-environment|How to use vagrant in a proxy environment?]] $ vagrant box list $ ### vagrant box add /c/distrs/ubuntu_20.04.box --name specialist/ubuntu20 $ ### vagrant box add generic/debian12 $ vagrant box add /c/distrs/debian12-generic.box --name generic/debian12 $ vagrant box list ===== Создание и управление VM ===== $ mkdir ~/nodes $ cd ~/nodes $ vagrant init specialist/ubuntu20 $ ###vagrant init generic/debian12 $ less Vagrantfile ... config.vm.box = "........" ... $ vagrant up $ ssh -p 2NNN vagrant@localhost $ vagrant ssh $ vagrant global-status $ ###vagrant global-status --prune $ vagrant halt $ vagrant destroy ===== Управление конфигурацией, использование переменных и Provision VM ===== * [[https://www.vagrantup.com/docs/provisioning|Provisioners in Vagrant]] * [[https://www.vagrantup.com/docs/provisioning/basic_usage|Basic Usage of Provisioners]] * [[https://www.vagrantup.com/docs/networking/public_network|Vagrant public networks]] ==== Внутри Vagrantfile ==== * [[https://stackoverflow.com/questions/30820949/print-message-after-booting-vagrant-machine-with-vagrant-up|Print message after booting vagrant machine with "vagrant up"]] * [[https://stackoverflow.com/questions/19648088/pass-environment-variables-to-vagrant-shell-provisioner|Pass environment variables to vagrant shell provisioner]] * !!! Зрелищнее - по очереди, config и provision λ cat Vagrantfile ... X = "13" Vagrant.configure("2") do |config| ### My config ### config.vm.post_up_message = "This is X: " + X config.vm.hostname = "node1.corp" + X + ".un" config.vm.network "private_network", adapter: 2, name: "VirtualBox Host-Only Ethernet Adapter", ip: "192.168." + X + ".201" config.vm.provider "virtualbox" do |vb| vb.memory = "2048" vb.cpus = "2" # file_to_disk = config.vm.hostname + '_disk2.vdi' # unless File.exist?(file_to_disk) # vb.customize ['createhd', '--filename', file_to_disk, '--size', 4 * 1024] # end # vb.customize ['storageattach', :id, '--storagectl', 'SATA или SATA Controller', '--port', 2, '--device', 0, '--type', 'hdd', '--medium', file_to_disk] end ### /My config ### ### My provision ### config.vm.provision "provision_once", type: "shell", inline: <<-SHELL apt-get update timedatectl set-timezone Europe/Moscow SHELL config.vm.provision "provision_onstart", run: "always", type: "shell", env: { "X" => X, }, inline: <<-SHELL eval `route -n | awk '{ if ($8 ==\"eth0\" && $2 != \"0.0.0.0\") print \"route del default gw \" $2; }'` route add default gw 192.168.$X.1 cat </etc/resolv.conf search corp$X.un nameserver 192.168.$X.10 EOF SHELL ### /My provision ### ... end λ vagrant validate λ vagrant up ... ==> default: Machine already provisioned ... ... λ vagrant ssh $ date λ vagrant up --provision λ ###vagrant provision --provision-with provision_once--provision-with provision_once λ ###vagrant reload --provision λ vagrant ssh $ date ==== Provision с использованием внешних скриптов ==== * [[https://stackoverflow.com/questions/15461898/passing-variable-to-a-shell-script-provisioner-in-vagrant|Passing variable to a shell script provisioner in vagrant]] vagrant.exe ssh node2 -c 'sudo apt install open-iscsi -y' vagrant.exe ssh node3 -c 'sudo apt install open-iscsi -y' λ touch provision_once.sh #!/bin/sh #echo 'root:strongpassword' | chpasswd #sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config #service ssh restart echo 'vagrant:strongpassword' | chpasswd (echo '"\e[A": history-search-backward'; echo '"\e[B": history-search-forward') >> /etc/inputrc timedatectl set-timezone Europe/Moscow apt update #apt install -y docker.io λ touch provision_onstart.sh #!/bin/bash X=$1 echo "$X" route add default gw 192.168."$X".1 eval "$(route -n | awk '{ if ($8 =="eth0" && $2 != "0.0.0.0") print "route del default gw " $2; }')" chattr -i /etc/resolv.conf echo -e "search corp$X.un\nnameserver 192.168.$X.10" > /etc/resolv.conf chattr +i /etc/resolv.conf echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/20-my-forward.conf && sysctl -p --system λ cat Vagrantfile ... config.vm.synced_folder ".", "/vagrant", disabled: false ... ### My provision ### ### /My provision ### ... vagrant@node1:~$ ls /vagrant/ vagrant@node1:~$ tr -d '\r' < /vagrant/provision_once.sh | shellcheck - vagrant@node1:~$ tr -d '\r' < /vagrant/provision_onstart.sh | shellcheck - λ cat Vagrantfile ### My provision ### config.vm.provision "provision_once", type: "shell", run: "once", path: "provision_once.sh" config.vm.provision "provision_onstart", type: "shell", run: "always", args: X + " 2_arg 3_arg", path: "provision_onstart.sh" ### /My provision ### ... λ vagrant provision --provision-with provision_once,provision_onstart server# ssh vagrant@node1 ==== Provision с использованием ansible ==== * Сервис Ansible [[Сервис Ansible#Использование playbook]] λ cat Vagrantfile ... config.vm.provision "provision_docker", type: "ansible_local", run: "once" do |ansible| ansible.playbook = "provision_docker.yml" end ... $ time vagrant provision --provision-with provision_docker real 11m2,127s ===== Multi-Machine Vagrant Environments ===== * [[https://blog.scottlowe.org/2014/10/22/multi-machine-vagrant-with-yaml/|Multi-Machine Vagrant with YAML]] * [[https://stackoverflow.com/questions/16708917/how-do-i-include-variables-in-my-vagrantfile|How do I include variables in my VagrantFile?]] λ vagrant destroy λ touch nodes.yaml - name: "node1" ip: "201" - name: "node2" ip: "202" - name: "node3" ip: "203" λ npp Vagrantfile ... require 'yaml' nodes = YAML.load_file("./nodes.yaml") Vagrant.configure("2") do |config| ### My config ### nodes.each do |opts| config.vm.define opts["name"] do |config| config.vm.network "private_network", adapter: 2, name: "VirtualBox Host-Only Ethernet Adapter", ip: "192.168." + X + "." + opts["ip"] config.vm.hostname = opts["name"] config.vm.provider :virtualbox do |vb| # vb.name = opts["name"] vb.memory = "2048" vb.cpus = "2" # file_to_disk = opts["name"] + '_2.vdi' # unless File.exist?(file_to_disk) # vb.customize ['createhd', '--filename', file_to_disk, '--size', 4 * 1024] # end # vb.customize ['storageattach', :id, '--storagectl', 'SATA', '--port', 2, '--device', 0, '--type', 'hdd', '--medium', file_to_disk] end end end ### /My config ### ... λ vagrant up node1 λ vagrant up λ vagrant status λ vagrant ssh node2 λ vagrant halt node2 λ vagrant destroy node1 λ vagrant destroy -f λ cd ~/conf/vagrant/nodes λ nano Vagrantfile #!!! set X and mem 1024 λ cat provision_once.sh # look passwords λ time vagrant up --parallel ===== Дополнительные возможности ===== ==== Еще варианты Multi-Machine Vagrant Environments ==== === Внутри Vagrantfile === * [[https://www.vagrantup.com/docs/multi-machine|Multi-Machine]] λ npp Vagrantfile ... Vagrant.configure("2") do |config| ### My config ### config.vm.define "node1" do |node1| node1.vm.network "private_network", ip: "192.168.X.201" end config.vm.define "node2" do |node2| node2.vm.network "private_network", ip: "192.168.X.202" end config.vm.define "node3" do |node3| node3.vm.network "private_network", ip: "192.168.X.203" end ### /My config ### ... === С использованием структур данных ruby === * [[https://github.com/hashicorp/vagrant/issues/9200|Vagrant is assigning the same MAC to two different VMs?]] boxes = [ { :name => "node1", :ip => "192.168.X.201", :vbox_config => [ { "--cpus" => "2" }, { "--memory" => "2048" } ], }, { :name => "node2", :ip => "192.168.X.202", :vbox_config => [ { "--cpus" => "2" }, { "--memory" => "2048" } ], }, { :name => "node3", :ip => "192.168.X.203", :vbox_config => [ { "--cpus" => "2" }, { "--memory" => "2048" } ], } ] Vagrant.configure("2") do |config| ### My config ### boxes.each do |opts| config.vm.define opts[:name] do |config| config.vm.network "private_network", ip: opts[:ip] config.vm.hostname = opts[:name] # config.vm.provider "virtualbox" do | vb | # file_to_disk = opts[:name] + '_2.vdi' # unless File.exist?(file_to_disk) # vb.customize ['createhd', '--filename', file_to_disk, '--size', 4 * 1024] # end # vb.customize ['storageattach', :id, '--storagectl', 'SATA', '--port', 2, '--device', 0, '--type', 'hdd', '--medium', file_to_disk] # end opts[:vbox_config].each do |hash| hash.each do |key, value| config.vm.provider :virtualbox do |vb| vb.customize ["modifyvm", :id, key, value] end end end end end ### /My config ### ... end === С использованием json === * [[Формат JSON]] * [[https://blog.scottlowe.org/2016/01/18/multi-machine-vagrant-json/|Multi-Machine Vagrant Environments with JSON]] λ npp nodes.json & [ { "name": "node1", "ip": "192.168.X.201", "vbox_config": [ { "--cpus": "2" }, { "--memory": "2048" } ] }, { "name": "node2", "ip": "192.168.X.202", "vbox_config": [ { "--cpus": "2" }, { "--memory": "2048" } ] }, { "name": "node3", "ip": "192.168.X.203", "vbox_config": [ { "--cpus": "2" }, { "--memory": "2048" } ] } ] $ cat Vagrantfile require 'json' boxes = JSON.parse(File.read('./nodes.json')) Vagrant.configure("2") do |config| ### My config ### boxes.each do |opts| config.vm.define opts["name"] do |config| config.vm.network "private_network", ip: opts["ip"] config.vm.hostname = opts["name"] opts["vbox_config"].each do |hash| hash.each do |key, value| config.vm.provider :virtualbox do |vb| vb.customize ["modifyvm", :id, key, value] end end end end end ### /My config ### ... end