Vagrantfile jest konfiguracją wirtualnej maszyny, która ma zostać zbudowana przez Vagranta. Jednak do tej pory mieliśmy do czynienia tylko z jedną wirtualną maszyną, a możliwe jest skonfigurowanie wielu maszyn w ramach jednego pliku Vagrantfile.
Jest to o tyle wygodne, że umożliwia nam postawienie np. serwera www niezależnie od bazy danych czy też innych usług, które później możemy bardzo łatwo wymieniać.
Dla naszych potrzeb postawimy 3 serwery www (Nginx) z czego jeden będzie tylko odpowiedzialny za równoważenie obciążenia pomiędzy dwoma pozostałymi.
Serwer ten nie będzie niczym wyszukanym, zastosujemy tutaj najprostsze rozwiązanie jakie daje nam Nginx. Definiujemy listę serwerów pomiędzy, które ma być rozdzielany ruch. Definicja ta powinna znaleźć się w pliku konfiguracyjnym server /etc/nginx/sites-enabled/default
upstream myapp {
server 192.168.10.101;
server 192.168.10.102;
}
Następnie dodajemy w definicji serwera server
w proxy_pass
wpis z naszą nazwą myapp
. Całość pliku będzie wtedy wyglądała następująco:
upstream myapp {
server 192.168.10.101;
server 192.168.10.102;
}
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
root /usr/share/nginx/html;
index index.html index.htm;
server_name localhost;
location / {
proxy_pass //myapp;
}
}
W ten oto sposób Nginx będzie przekierowywał ruch raz na jedną raz na drugą maszynę. Zapisujemy go pod nazwą nginx-load-balancing
w katalogu vagrant_files
i będziemy kopiować do wirtualnej maszyny jako nowo obowiązujący plik konfiguracyjny.
Czas na tej podstawie przygotować plik Vagrantfile, tworzący odpowiednią wirtualną maszynę.
Vagrant.configure("2") do |config|
config.vm.define "lb" do |lb|
lb.vm.box = "ubuntu/xenial64"
lb.vm.network "private_network", ip: "192.168.10.100"
lb.vm.provision "shell", inline: <<-SHELL
sudo apt-get update
sudo apt-get install -y nginx
sudo service nginx stop
sudo cp /vagrant/vagrant_files/nginx-load-balancing /etc/nginx/sites-enabled/default
sudo service nginx start
sudo echo "Load Balancing" >> /var/www/html/index.html
SHELL
end
end
Jeśli czytaliście moje poprzednie wpisy dotyczące Vagrant-a, to jedyna nowa rzecz to config.vm.define
. Jest to zapis pozwalający na zdefiniowanie wielu maszyn wirtualnych w ramach jednego pliku Vagrantfile.
config.vm.define "lb" do |lb|
Konstrukcja jest banalna, zaczynamy od odwołania się do nazwy naszej konfiguracji, czyli w tym przypadku config
. Następnie stała vm.define
oraz podajemy własną nazwę pod którą będziemy definiować wirtualną maszynę. W moim przypadku "lb"
i przypisujemy ją do nazwy |lb|
. Pozostała część już powinna być wam znana 😉
Uruchamiamy tworzenie maszyny poleceniem vagrant up
i po wejściu na stronę zobaczymy taki komunikat:
Wynika to z faktu nie podsiadania żadnego serwera www, który obsłużył by nasz ruch.
Skoro mamy już maszynę, która balansuje nasz ruch to stwórzmy serwery obsługujące ten ruch. Będziemy bazować na tym co dodaliśmy w poprzedniej maszynie, gdyż jedyna różnica w ich przypadku to strona która będzie wyświetlana.
Zaczynamy od przygotowania pliku dla Nginx-a, który będzie wyświetlał tylko prostą statyczną stronę z nazwą maszyny wirtualnej. Dzięki temu możliwe będzie obserwowanie przełączania ruchu pomiędzy maszynami.
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
root /usr/share/nginx/html;
index index.html index.htm;
server_name localhost;
location / {
try_files $uri $uri/ =404;
}
}
Zapiszemy tę konfigurację w pliku nginx-web
w katalogu vagrant_files
. Teraz dodamy nową definicję serwera www do pliku Vagrantfile
.
config.vm.define "web1" do |web1|
web1.vm.box = "ubuntu/xenial64"
web1.vm.network "private_network", ip: "192.168.10.101"
web1.vm.provision "shell", inline: <<-SHELL
sudo apt-get update
sudo apt-get install -y nginx
sudo service nginx stop
sudo cp /vagrant/vagrant_files/nginx-web /etc/nginx/sites-enabled/default
sudo service nginx start
sudo echo "WEB 1" >> /var/www/html/index.html
SHELL
end
Niszczymy poprzednio zdefiniowaną maszynę poleceniem vagrant destroy -f
, a następnie uruchamiamy tworzenie maszyn zdefiniowanych w zmodyfikowanym pliku Vagrantfile poleceniem vagrant up
. Po stworzeniu maszyn i przejściu na stronę pod adresem load balancer-a http://192.168.10.100
powinniśmy zobaczyć stronę:
Ostatni krok to stworzenie jeszcze jednej wirtualnej maszyny wyświetlającej stronę www. Kopiujemy poprzednią definicję zmieniając jedynie nazwę definicji, adres IP oraz wyświetlany plik html.
config.vm.define "web2" do |web2|
web2.vm.box = "ubuntu/xenial64"
web2.vm.network "private_network", ip: "192.168.10.102"
web2.vm.provision "shell", inline: <<-SHELL
sudo apt-get update
sudo apt-get install -y nginx
sudo service nginx stop
sudo cp /vagrant/vagrant_files/nginx-web /etc/nginx/sites-enabled/default
sudo service nginx start
sudo echo "WEB 2" >> /var/www/html/index.html
SHELL
end
I ponownie niszczymy maszynę poleceniem vagrant destroy -f
i ją odbudowujemy vagrant up
. Po chwili, gdy wszystkie wirtualne maszyny zostaną zbudowane wchodzimy na load balancer dostępny pod adresem http://192.168.10.100
. Teraz każde odświeżenie strony powinno powodować wyświetlenie nazwy innej wirtualnej maszyny która obsłużyła ruch.
W ten oto prosty sposób otrzymaliśmy prosty system równoważący obciążenie. Nic nie szkodzi na przeszkodzie, aby dodać dodatkowy serwer, który odciąży dwa pozostałe.
Definicje serwerów www zawierają elementy powtarzalne, takim elementem jest instalacja oprogramowania na wirtualnych maszynach. Zobaczmy jak możemy to zoptymalizować.
Zacznijmy od przeniesienia kodu do pliku install_web.sh
w katalogu vagrant_files
. Będzie on wyglądał następująco:
sudo apt-get update
sudo apt-get install -y nginx
sudo service nginx stop
sudo cp /vagrant/vagrant_files/nginx-web /etc/nginx/sites-enabled/default
sudo service nginx start
sudo echo "WEB 1" >> /var/www/html/index.html
Jednaj jeden element nie jest tutaj wspólny, mianowicie w tworzonych plikach html wpisana jest inna nazwa serwera. To nic bowiem możemy przekazywać parametry do plików definiowanych w provision
typu shell
. Oto zmieniony wpis dla pierwszego serwera:
web1.vm.provision :shell do |shell|
shell.args = "WEB1"
shell.path = "vagrant_files/install_web.sh"
end
Teraz zamiast zapisu w linii, mamy blok konfiguracji o nazwie shell
. W bloku tym została ustawiona lista parametrów (args
) przekazywanych do pliku, gdzie przekazywany jest tylko jeden argument o treści WEB1
. Z naszej nazwy zniknęła spacja, gdyż spacją rozdzielane są poszczególne argumenty.
Kolejny parametr to path
czyli ścieżka do pliku, który ma zostać uruchomiony w powłoce i do którego przekazać argumenty.
W pliku odbieramy argumenty, które są dostępne pod znakiem dolara i numerem argumentu. Dla naszej definicji argument będzie dostępny pod $1
. W związku z czym zmieniamy jego definicję na:
sudo apt-get update
sudo apt-get install -y nginx
sudo service nginx stop
sudo cp /vagrant/vagrant_files/nginx-web /etc/nginx/sites-enabled/default
sudo service nginx start
sudo echo $1 >> /var/www/html/index.html
Po czym nanosimy analogiczną zmianę w konfiguracji drugiego serwera www.
web2.vm.provision :shell do |shell|
shell.args = "WEB2"
shell.path = "vagrant_files/install_web.sh"
end
Zapisujemy zmiany, niszczymy maszyny vagrant destroy -f
i odbudowujemy je na nowo vagrant up
. Po odbudowie maszyn nie powinniśmy zobaczyć żadnej różnicy, oczywiście poza krótszym plikiem Vagrantfile 😉
Przedstawione rozwiązanie pokazuje jedynie jak możemy w prosty sposób definiować wiele maszyn, oraz jak na tej bazie prosto wykonać load balancing wykorzystując Nginx-a.
Wiadomą sprawą jest że kod aplikacji na maszynach powinien być identyczny, tutaj zaś jego zróżnicowanie miało jedynie na celu pokazać działanie rozwiązania.
Dla leniwych pełna konfiguracja dostępna jest na GitHub-ie 😉