====== Технология 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