Środowisko dla Docker Swarm

Odświeżałem ostatnio wiadomości z podstaw używania Docker Swarm. Do stworzenia klastra do ćwiczeń zdecydowałem się użyć Vagrant-a. To narzędzie dzięki któremu w prosty sposób mogę szybko stworzyć kilka maszyn wirtualnych, połączyć się z nimi itd. - Vagrant zadba o stworzenie kluczy SSH i całą resztę. Nie trzeba “przeklikiwać” się przez każdą z nich indywidualnie.

Trochę bardziej nietypową częścią było to, że te vm-ki były uruchamiane… w innej vm-ce (zagnieżdżona wirtualizacja). To może operacja nieco na wyrost - ale przyznaję, że do ćwiczeń lubię to podejście. Dzięki temu ucząc się nie mam obaw, że zrobię coś głupiego i uziemię swoją stację roboczą - w razie czego mogę usunąć “popsutą” maszynę wirtualną i odtworzyć ją na nowo. W mojej ocenie prowadzi to do zdecydowanie odważniejszych ćwiczeń - a tym samym lepszej sesji treningowej.

Przygotowanie maszyny do ćwiczeń

Jako system do ćwiczeń wybrałem Rocky Linuxa z pulpitem Gnome. Wybór wirtualizatora to kwestia indywidualna - stąd też nie ma sensu, żebym rozpisywał się na ten temat. Ważne żeby umożliwiał uruchamianie vm-ek wewnątrz vm-ek. W większości wypadków wystarczy pobrać obraz instalacyjny i przeklikać się przez konfigurator (w moim wypadku KVM i Virt-Manger jako GUI). Po uruchomieniu zaktualizowałem system i przeszedłem do właściwej pracy (i od tego momentu reszta kroków wykonywana jest bezpośrednio na vm-ce).

  1. Sprawdzenie czy jest aktywana zagnieżdżona wirtualizacja

https://docs.fedoraproject.org/en-US/quick-docs/using-nested-virtualization-in-kvm/

  1. Dodanie narzędzi do wirtualizacji.
sudo dnf group install -y "virtualization hypervisor"
sudo dnf group install -y "virtualization tools"
sudo systemctl enable --now libvirtd

Uruchomiono też libvirt-a i dodano użytkownika do grupy libvirt.

sudo systemctl enable libvirtd --now
sudo usermod -aG libvirt <UŻYTKOWNIK>

Instalacja Dockera

  1. Dodano repozytorium dla Dockera
sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo
  1. Instalacja
sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
  1. Uruchomiono usługę
systemctl enable docker --now
  1. Dodano użytkownika do grupy docker
usermod -aG docker <UŻYTKOWNIK>

Vagrant do startowania dodatkowych węzłów

  1. Dodano repozytorium z Vagrant-em i zainstalowano go.
sudo dnf config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
sudo dnf install -y vagrant
  1. Zainstalowano plugin dla libvirt - wymagało to dodanie libvirt-devel i development tools
sudo dnf config-manager --set-enabled crb
sudo dnf groupinstall 'Development Tools'
sudo dnf install -y libvirt-devel
vagrant plugin install vagrant-libvirt

Definicja Vagrant

Wykorzystany został box:

https://portal.cloud.hashicorp.com/vagrant/discover/formationgpa/r9docker

Zawiera on od razu zainstalowanego Dockera. Jest to jednak box dostarczony przez społeczność, więc w jakiś poważniejszych zastosowaniach warto by było bliżej się mu przyjrzeć.

Stworzono folder dla projektu i przygotowano następujacy Vagrantfile:

Vagrant.configure("2") do |config|
  swarm = [
    {
      hostname: "node1",
      box: "formationgpa/r9docker",
      ip: "10.20.30.10"
    },
    {
      hostname: "node2",
      box: "formationgpa/r9docker",
      ip: "10.20.30.20"
    },
    {
      hostname: "node3",
      box: "formationgpa/r9docker",
      ip: "10.20.30.30"
    },
    {
      hostname: "node4",
      box: "formationgpa/r9docker",
      ip: "10.20.30.40"
    }
  ]

  swarm.each do |machine|
    config.vm.define machine[:hostname] do |node|
      node.vm.box = machine[:box]
      node.vm.hostname = machine[:hostname]
      node.vm.network "private_network",
        ip: machine[:ip]
      node.vm.synced_folder ".", "/vagrant", disabled: true
      node.vm.provider "libvirt" do |lv|
        lv.cpu_mode = "host-passthrough"
        lv.cpus = 2
        lv.memory = 2048
      end
    end
  end

end

To nic innego jak krótki skrypt napisany w Ruby - na pewno dałoby radę go zoptymalizować. Jednak z racji tego, że nie znam tego języka zapoznałem się jedynie z podstawową składnią i strukturami danych, tak aby być w stanie stworzyć taką podstawową konfigurację. Z racji tego, że ilość węzłów nie idzie w setki, dodatkowe VM-ki mogę dodać poprzez kopiowanie i dodawanie nowych wpisów w liście swarm.

Oczywiście dla innych wirtualizatorów należałoby wprowadzić odpowiednie modyfikacje w sekcji provider.

Taki plik można zweryfikować poprzez:

vagrant validate

Jeśli wszystko jest ok to pozostaje stworzyć i uruchomić vmk-ki poprzez:

vagrant up

Chcąc wyłączyć je należy:

vagrant halt

A usunąć je można poprzez:

vagrant destroy

Status można podejrzeć z pomocą:

vagrant global-status

Swarm w działaniu

Po uruchomieniu VM-ek można było się do nich zalogować poprzez vagrant ssh <NAZWA> i uruchomić lidera swarma na jednej z nich poprzez:

docker swarm init --adverise-addr <ADRES_IP>

Na kolejnych wystarczy użyć wyświetlonego linka żeby dołączyć do swarm-a.

Przy okazji - do podzielenia terminala na części wykorzystuję Zellij. Ten multiplexer daje też możliwość zapisywania sesji - więc upraszcza pracę. Równie dobrze można by było użyć Tmuxa - wymaga jednak on wg. mnie nieco więcej pracy w konfiguracji. W Zellij-u musiałem jedynie zadbać o to,  żeby poprawnie działało kopiowanie tekstu:

https://zellij.dev/documentation/faq#copy--paste-isnt-working-how-can-i-fix-this

Pozostaje zacząć zabawę - uruchomić jakąś usługę np.

docker service create alpine ping 8.8.8.8

Spróbować “ubić” kontener na którymś z węzłów i zobaczyć jak swarm go przywraca itd. (a finalnie usunąć poprzez docker service rm <NAZWA>).

Gorąco też polecam ten kurs na Udemy:

https://www.udemy.com/course/docker-mastery

Odnośniki

https://vagrant-libvirt.github.io/vagrant-libvirt/configuration.html

https://developer.hashicorp.com/vagrant/docs/networking/basic_usage

https://developer.hashicorp.com/vagrant/docs/

https://www.youtube.com/watch?v=a9pHnOkhcds

https://reintech.io/blog/working-with-data-structures-in-ruby

Obrazek(-ki):

Rémi Boudousquié @Unsplash

Przemek