====== Wirtualizacja na poziomie systemu operacyjnego ====== ===== Wstęp ===== ==== LXC (Linux Kernel Containers) ==== Kontenery wspierane przez system Linux (LXC - Linux Containers) są jedną z najnowocześniejszych metod wirtualizacji aplikacji. LXC pozwala na przydział zasobów CPU, pamięci, dysków i sieci dla odizolowanych aplikacji od systemu operacyjnego. LXC separuje drzewa procesów, dostęp do sieci, ID użytkownika, dostęp do plików. LXC jest techniką funkcjonalnie umiejscawianą pomiędzy rozwiązaniem chroot oraz VM. Kontenery Linux są elastyczne, ponieważ pozwalają administratorowi wirtualizować pojedynczą aplikację, a nie cały system operacyjny z wykorzystaniem VM. Nie ma potrzeby zakupów dodatkowych licencji na systemy operacyjne, tak jak ma to miejsce w przypadku wirtualizacji. LXC oferuje także stosunkowo niewielki narzut systemu operacyjnego, ponieważ aplikacje wykorzystują standardowe wywołania systemowe oraz połączenia do interfejsów z lekkim systemem operacyjnym OS. Przykładowo w takich zastosowaniach warto rozważyć dystrybucję CoreOS. ==== Docker ==== Docker jest aplikacją pracującą na podbudowie w postaci LXC, która zarządza obrazami oraz asystuje we wdrożeniach wirtualizacji aplikacji. Dostarcza automatyzacji oraz mechanizmów szybkiego tworzenia kontenerów LXC. Dodatkowo udostępnia API, które rozszerza funkcjonalność LXC o możliwość budowania oferty PaaS (Platform as a Service). Docker pierwotnie nazywał się dotCloud, a jego kariera trwa od roku. Aktualnie jest zintegrowany z szeregiem innych narzędzi m.in. Ansible, Chef, OpenStack, Pupper, Salt. Jest też dołączony do RHEL, OpenShift PaaS, Google Compute Engine, Deis, a także Amazon Web Services Elastic Beanstalk. Docker jest aktualnie standardem wirtualizacji aplikacji dla systemu Linux. Z racji na czasochłonne tworzenie kontenera LXC (ok. 55 minut), proszę przed rozpoczęciem wykonywania ćwiczeń wykonać instrukcje zawarte w punktach: * 5.2. * 5.3. * 5.4. * 6.1.II W trakcie tworzenia kontenera (ostatni podpunkt) można przejść do wykonywania instrukcji od początku. W przypadku dotarcia do momentu tworzenia kontenera LXC, kontener nie będzie jeszcze gotowy, proszę rozpocząć ćwiczenie dotyczące [[#docker1|Docker-a]]. ===== Control Groups ===== ==== - Montowanie Control Groups ==== - Sprawdzić czy ''cgroups'' są zamontowane:mount - Jeżeli wszystko jest OK, to wśród zamontowanych systemów plików powinno pojawić się coś na wzór:tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755) cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd) cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset,clone_children) cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct) cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices) cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer) cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio) cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio) cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event) - Jeżeli ''cgroups'' nie są zamontowane należy wykonać następujące kroki: - Dodać następującą linię w pliku ''/etc/fstab''cgroup /sys/fs/cgroup cgroup defaults 0 0 - Spróbować zamontować poleceniem: mount /sys/fs/cgroup - W przypadku otrzymania informacji o zajętości zasobów (//resource busy problem//) należy zrestartować system. ==== - Tworzenie nowych grup ==== - Tworzenie nowej grupy polega na stworzeniu folderu w ramach systemu plików ''cgroup'' w odpowiednim kontrolerze. - Listę wszystkich kontrolerów można zobaczyć wpisując jedno z poniższych poleceń: - Wpisując ''mount'' -- każdy punkt montowania to jeden kontroler. - Wyświetlając listę grup procesu ''init'': cat /proc/1/cgroup - Wchodząc bezpośrednio do odpowiedniego katalogu np.cd /sys/fs/cgroup ls -l - Nową grupę można utworzyć używając polecenia ''cgcreate'' (przeczytaj manual):cgcreate [-h] [-t :] [-a :] [-f mode] [-d mode] [-s mode] -g : [-g ...] - Tworzymy nową grupę o nazwie ''cpulimited'' w ramach controlera ''cpu'':cgcreate -g cpu:/cpulimited - Sprawdzamy czy dana grupa istnieje pobierając wszystkie jej ustawienia:cgget -g cpu:/cpulimited - Można też wykonać polecenie: ls -l /sys/fs/cgroup/cpu/cpulimited ==== - Uruchamianie procesów ==== - Uruchamiamy program ''cat'':cat - Używając programu ''ps'' odnajdujemy PID uruchomionego procesu programu ''cat''. - Sprawdzamy w jakiej grupie jest uruchomiony powyższy proces:cat /proc/PID/cgroup - W folderach, które odpowiadają odpowiednim kontrolerom znajduje się plik ''tasks''. Używając tego pliku sprawdź czy PID powyższego procesu znajduje się w kontrolerach ''cpu'' oraz ''blkio'' należących do grupy, w której pracuje proces np.:cat /sys/fs/cgroup/cpu/CGROUP/tasks | grep PID - Przenieś uruchomiony proces do wcześniej stworzonej grupy ''cpulimited''. Przeniesienie procesu jest możliwe na dwa sposoby (spróbuj wykonać ćwiczenie używając każdego z nich): - Użycie polecenia ''cgclassify'' (przeczytaj manual):cgclassify -g cpu:/cpulimited PID - Zapisanie PID procesu do pliku ''tasks'':echo PID > /sys/fs/cgroup/cpu/cpulimited/tasks - Po każdym przeniesieniu sprawdź czy grupa procesu rzeczywiście się zmieniła: \\ Przykład przed:# cat /proc/32194/cgroup 8:perf_event:/ 7:blkio:/ 6:net_cls,net_prio:/ 5:freezer:/ 4:devices:/user.slice 3:cpu,cpuacct:/ 2:cpuset:/ 1:name=systemd:/user.slice/user-1000.slice/session-1.scopePrzykład po:# cat /proc/32194/cgroup 8:perf_event:/ 7:blkio:/ 6:net_cls,net_prio:/ 5:freezer:/ 4:devices:/user.slice 3:cpu,cpuacct:/cpulimited 2:cpuset:/ 1:name=systemd:/user.slice/user-1000.slice/session-1.scope - Aby uruchomić proces od razu w zadanej grupie należy użyć polecenia ''cgexec'' (przeczytaj manual). - Zakańczamy działanie uruchomionego procesu ''cat'' i uruchamiamy go ponownie, tym razem przy pomocy powyższego polecenia od razu w grupie ''cpulimited'':cgexec -g cpu:/cpulimited cat - Analogicznie jak poprzednio: Sprawdzamy czy proces jest uruchomiony w zadanej grupie. - Zakańczamy proces. ==== - Definiowanie ograniczeń ==== - Wyświetlamy zdefiniowane ograniczenie zużycia procesora w głównej i zdefiniowanej grupie ''cpulimited'':cgget -r cpu.shares / cgget -r cpu.shares /cpulimitedObydwie wartości powinny być sobie równe. - Zmieniamy ograniczenie w naszej zdefiniowanej grupie na wartość 512. Można to zrobić na dwa sposoby: - Przy pomocy ''echo'':echo 512 > /sys/fs/cgroup/cpu/cpulimited/cpu.shares - Przy pomocy dedykowanego polecenia ''cgset'' (przeczytaj manual):cgset -r cpu.shares=512 /cpulimited - Ponownie wyświetlić wartości ustawień w obydwóch grupach aby sprawdzić czy otrzymaliśmy zamierzony efekt. - Testujemy nasze ustawienia: - Instalujemy program ''matho-primes''. Należy samodzielnie znaleźć nazwę pakietu do doinstalowania np. przy pomocy wyszukiwarki na stronie: [[https://www.debian.org/distrib/packages#search_packages]] - Sprawdzamy ile mamy procesorów:lscpu - Program ''matho-primes'' uruchamiamy w głównej grupie tyle razy ile mamy procesorów (aby upewnić się, że każdy będzie obciążony). - W tym celu wywołujemy poniższą komendę zadaną ilość razy:matho-primes 0 9999999999 > /dev/null & - Sprawdzamy obciążenie procesora używając ''top''. - Przy pomocy poznanych sposobów uruchamiamy kolejną instancję programu jednak tym razem w grupie ''cpulimited''. - Ponownie sprawdzamy obciążenie procesora i próbujemy zaobserwować różnice w obciążaniu: PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1556 root 20 0 9116 3248 1356 R 88,4 0,0 0:54.89 matho-primes 1557 root 20 0 9116 3220 1316 R 88,1 0,0 0:54.41 matho-primes 1558 root 20 0 9116 3208 1308 R 87,4 0,0 0:54.56 matho-primes 1555 root 20 0 9116 3260 1364 R 86,1 0,0 0:55.41 matho-primes 1554 root 20 0 9116 3220 1316 R 41,6 0,0 0:27.02 matho-primesW powyższym przykładzie proces 1554 został uruchomiony w grupie ''cpulimited''. Jak widzimy obciąża on procesor około 50% mniej w porównaniu z innymi procesami. - Zamknąć wszystkie procesy działające w głównej grupie (proszę nie zakańczać procesu z grupy ''cpulimited''): - Jakie jest teraz obciążenie? - Jak wyjaśnić to zjawisko? - Pełna dokumentacja: [[https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Resource_Management_Guide/index.html]] ===== LXC ===== W poniższej instrukcji ''NAME'' oznacza wybraną nazwę maszyny wirtualnej. ==== - Instalacja ==== - Instalacja LXC jest bardzo prosta. Wszystkie potrzebne pakiety znajdują się w repozytorium. - Aktualizujemy listę pakietów:apt-get update - Instalujemy pakiety LXC:apt-get install lxc - Dodatkowo można zainstalować (w celu ułatwienia pracy):apt-get install bridge-utils libvirt-bin debootstrap - Sprawdzamy konfigurację:lxc-checkconfig - Sprawdzamy zainstalowane/dostępne narzędzia:lxc- ==== - Tworzenie kontenerów ==== - Tworzenie kontenerów odbywa się przy pomocy polecenia ''lxc-create'': - Przeczytać manual do polecenia. - Tworzymy obraz najnowszej dystrybucji debiana:lxc-create -n NAME -t debian -- -r jessie - Po utworzeniu obrazu, wyświetli się nam informacja o konfiguracji w tym hasło ''root''-a do naszej maszyny wirtualnej. - Pliki maszyny wirtualnej znajdują się w katalogu: ''/var/lib/lxc/NAME/''. - Jednym z folderów jest ''rootfs'', który jest montowany w maszynie wirtualnej jako główny system plików. - Wykorzystując ten fakt, zmieniamy hasło ''root''-a do naszej maszyny wirtualnej: - Zmieniamy katalog główny na ''rootfs'':chroot rootfs - Wywołujemy polecenie ''passwd''. - Zmieniamy hasło. - Wciskamy ''Ctrl-D'' - powłoka powinna powrócić do poprzedniego katalogu głównego. ==== - Uruchomienie kontenera ==== - Polecenie ''lxc-start'' służy do uruchamiania kontenera: - Przeczytać manual do polecenia, zwrócić uwagę na opcję ''-d''. - Uruchomić maszynę wirtualną poleceniem: lxc-start -n NAME - Logujemy się na konto ''root''-a, przy pomocy zmienionego hasła. - Poleceniem ''lxc-stop'' (przeczytać manual) można zakończyć działania maszyny wirtualnej w sposób //czysty// lub //wymuszony// (opcja ''-k''): - Zatrzymujemy naszą maszynę:lxc-stop -n NAME ==== - Przestrzenie nazw i Control groups ==== - Uruchamiamy maszynę wirtualną. - Po jej uruchomieniu sprawdzamy identyfikator procesu ''init'':ps uax | grep init - W systemie gospodarza wykonujemy identyczną komendę: - Ile procesów ''init'' pojawia się na liście? - Który z nich dotyczy maszyny wirtualnej? - Sprawdzamy identyfikatory przestrzeni nazw dla obydwóch procesów:ls -l /proc/1/ns ls -l /proc/INITPID/ns - Czy identyfikatory są różne? - Które z nich są takie same? - Zwróć uwagę na identyfikator ''net'', czy są one sobie równe? - W maszynie wirtualnej uruchamiamy proces ''cat'':cat - W systemie gospodarza próbujemy wyszukać ten proces w liście wszystkich procesów:ps aux | grep cat - Czy taki proces istnieje? - Jeżeli tak, to: - Wyświetl identyfikatory jego przestrzeni nazw. - Czy są one takie same jak w przypadku któregoś z procesów ''init''? - Co to oznacza? - Spróbuj go zakończyć przy pomocy ''kill''. - Czy proces w maszynie wirtualnej zakończył się? - Jeżeli nie, to jak to wyjaśnić? - Sprawdź czy LXC rzeczywiście korzysta z Control Groups: - Wejdź do katalogu ''/sys/fs/cgroup/'' w wyszukaj w nim pliki o nazwie ''NAME'':find . -name \*NAME\* - Jeżeli pojawiają się jakieś wyniki, to znaczy, że LXC tworzy swoje grupy. - Spróbuj także użyć polecenia ''lxc-cgroup'' (przeczytaj manual) np.:lxc-cgroup -n NAME cpu.shares - Sprawdź czy oprócz tworzenia swoich grup, LXC uruchamia procesy w tych grupach: - Wyświetl plik ''tasks'' np. w kontrolerze ''cpu'' grupy odnoszącej się do uruchomionej maszyny wirtualnej:cat /sys/fs/cgroup/cpu/lxc/NAME/tasks - Czy wyświetla się jakiś identyfikator? - Jakiego procesu on dotyczy? ==== - Konfiguracja sieci ==== - Sprawdź czy jest połączenie z internetem w twojej maszynie wirtualnej. Możesz to zrobić wywołując polecenie:apt-get update - Sprawdź jakie interfejsy sieciowe są aktywne w twoim systemie wirtualnym. - W systemie gospodarza, sprawdź konfigurację sieci twojej maszyny wirtualnej: - Wyświetl plik konfiguracyjny: less /var/lib/lxc/NAME/config - Jaka jest wartość opcji ''lxc.network.type''? - Co ona oznacza? (sprawdź manual ''lxc.container.conf(5)'') - Zmień ustawienie na ''none''. - Wykonaj restart maszyny wirtualnej przy pomocy polecenie ''lxc-stop'' a później ''lxc-start''. - Sprawdź jakie interfejsy sieciowe są w systemie wirtualnym. - Ponownie wykonaj test czy jest połączenie z internetem. - Na maszynie gospodarza ponownie porównaj identyfikatory przestrzeni nazw ''net'', czy są one takie same? - Zatrzymaj swoją maszynę wirtualną przy pomocy ''lxc-stop''. - Czy działa połączenie z internetem w systemie gospodarza? - Czy takiego efektu można było się spodziewać. - Skonfiguruj ponownie swoje interfejsy w systemie gospodarza - doprowadź sieć do działania. - Zmień konfigurację sieci twojego kontenera: - Zmień ustawienie parametru ''lxc.network.type'' na ''veth''. - Poniżej dodaj dwa kolejne wpisy: - Automatyczne aktywowanie interfejsów sieciowych podczas startu maszyny: ''lxc.network.flags = up'' - Nazwa mostka sieciowego przez który maszyna będzie się łączyć z siecią: ''lxc.network.link = lxcbr0'' - Następnie należy dostosować konfigurację systemu gospodarza: - Stwórz i skonfiguruj mostek sieciowy: brctl addbr lxcbr0 brctl addif lxcbr0 eth0 - Usuń przypisane IP z dotychczasowego interfejsu i przypisz go do mostka: ifconfig eth0 0.0.0.0 dhclient lxcbr0 - Uruchom maszynę wirtualną i sprawdź dostęp do sieci w systemie gospodarza i na maszynie wirtualnej. - Zatrzymaj maszynę wirtualną i sprawdź dostęp do sieci w systemie gospodarza. ==== - Uruchamianie procesów w kontenerze ==== - W kontenerze można pracować jak w na normalnym systemie operacyjnym. Pierwszym zadaniem będzie pobranie, skompilowanie i uruchomienie aplikacji z ''github''-a: - Uruchom kontener. - Zainstaluj ''git''-a:apt-get install git - Sklonuj repozytorium: git clone https://github.com/fsuplicy/bubbleSort.git - Spróbuj skompilować:gcc -o bubbleSort bubbleSort.cW razie braku kompilatora doinstaluj odpowiednie pakiety. - Uruchom program:./bubbleSort test_data/extralarge.txt - Wykonaj restart kontenera i sprawdź czy po ponownym uruchomieniu pliki programu ''bubbleSort'' dalej istnieją w kontenerze. - Drugim przypadkiem użycia kontenerów jest uruchamianie procesów w odizolowanym środowisku. - Używając polecenia ''lxc-execute'' (przeczytać manual) uruchom program ''echo''. Przykładowa komenda do uruchomienia może wyglądać następująco:echo "test OK" - W przypadku komunikatów o błędzie, doinstaluj pakiet zawierający brakujący plik - nazwę pakietu możesz wyszukać [[https://www.debian.org/distrib/packages#search_packages|tutaj]]. - Po znalezieniu nazwy pakietu użyj następującego polecenia aby go zainstalować:apt-get install --no-install-recommends NAZWA_PAKIETU - Jeżeli instalacja przebiegła pomyślnie, to ponownie spróbuj uruchomić powyższy przykład. Jeżeli na konsoli pojawi się napis //test OK// to oznacza, że wszystko przebiegło pomyślnie. - Używając polecenia ''lxc-execute'' uruchom program ''bubbleSort''. Przykładowa komenda do uruchomienia może wyglądać następująco:lxc-execute -n NAME -- /root/bubbleSort/bubbleSort /root/bubbleSort/test_data/large3.txt ===== Docker ===== ==== - Instalacja ==== - Poniższa instrukcja dotyczy instalacji narzędzia na systemie Debian w wersji Jessie. - Wszystkie instrukcje należy wykonać jako ''root''. - Weryfikacja wersji jądra: Docker wymaga jądra w wersji co najmniej 3.10. W celu weryfikacji czy system spełnia to wymaganie należy wpisać:uname -r - Wyczyść ewentualne stare wersje pakietów:apt-get purge lxc-docker* docker.io* - Narzędzie Docker jest pobierane z osobnej lokalizacji (nie ze standardowych repozytoriów Debiana), dlatego należy dodać nowe repozytorium do pliku: ''/etc/apt/sources.list'': - Otwieramy plik w dowolnym edytorze i na jego końcu dodajemy wpis:# Docker deb https://apt.dockerproject.org/repo debian-jessie main - Generujemy nowy klucz dla programu ''apt'', który posłuży do weryfikacji pakietów instalowanych z repozytorium Docker-a:apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D - Wykonujemy aktualizację listy pakietów:apt-get update - Jeżeli wystąpiły błędy mówiące o tym, że nie ma sterownika dla metody przesyłania pakietów ''https'', należy go doinstalować: - Najpierw należy zakomentować dodany URL repozytorium dodając na początku linii znak ''#''. - Wykonujemy aktualizację pakietów. - Instalujemy brakujący sterownik:apt-get install apt-transport-https - Usuwamy znak komentarza. - Ponownie wykonujemy aktualizację pakietów. - Instalujemy pakiety Docker-a:apt-get install docker-engine - Uruchamiamy demona systemowego:service docker start - Na stronie [[https://docs.docker.com/engine/installation/debian]] znajduje się szczegółowa instrukcja dotycząca instalacji Docker-a. Można na niej znaleźć informacje dotyczące instalacji na innych wersjach Debiana a także innych systemach operacyjnych (w tym na Windows-ie). ==== - Pobranie obrazu i uruchomienie kontenera ==== - Aby stworzyć kontener przy pomocy Docker-a, należy uruchomić odpowiedni obraz. Jeżeli obraz nie istnieje lokalnie to zostanie on pobrany ze zdalnego repozytorium. - Uruchamiamy kontener o nazwie ''debian'':docker run -it debian - Przeczytać w manualu co oznaczają opcje powyższego polecenia. - W drugiej konsoli sprawdź: - Listę obrazów:docker images - Listę kontenerów:docker ps - Uruchom kolejny kontener z tego samego obrazu:docker run -it debianPonownie sprawdź listę obrazów i kontenerów. - Jaka jest relacja pomiędzy kontenerem a obrazem? - Zatrzymaj jeden z kontenerów przy pomocy polecenia ''docker stop CONTAINER'': - W celu uzyskania identyfikatora kontenera ''CONTAINERID'' wywołajdocker ps - Zatrzymaj kontener:docker stop CONTAINERID ==== - Przestrzenie nazw i Control groups ==== - Uruchamiamy kontener. - Po jego uruchomieniu uruchamiamy dowolny program np. ''cat'':cat - Na maszynie hosta wyszukujemy uruchomiony proces:ps uax | grep catCzy taki proces istnieje? - Sprawdzamy identyfikator procesu ''cat'' (''CATPID''). - Wyświetlamy identyfikatory przestrzeni nazw w których pracuje:ls -l /proc/CATPID/nsCzy są one takie same jak w przypadku procesu ''init''? - Sprawdzamy Control Groups w jakich uruchomiony został proces:cat /proc/CATPID/cgroup - Sprawdź czy oprócz tworzenia swoich grup, Docker uruchamia procesy w tych grupach: - Wyświetl plik ''tasks'' np. w kontrolerze ''cpu'' grupy odnoszącej się do uruchomionej maszyny wirtualnej. - Czy oprócz identyfikaotra procesu ''cat'' wyświetla się jeszcze jakiś identyfikator? - Jakiego procesu on dotyczy? - Spróbuj zakończyć proces ''cat'' przy pomocy ''kill''. Czy proces w maszynie wirtualnej zakończył się? - Analogicznie spróbuj zakończyć drugi proces. Co się stało z maszyną wirtualną? ==== - Stan kontenera ==== - W uruchomionym kontenerze przejdź do katalogu domowego. - Stwórz w tym katalogu dowolny plik. - Zatrzymaj kontener przy pomocy ''docker stop CONTAINER''. - Uruchom kontener ponownie przy pomocy ''docker run''. - Sprawdź czy stworzony plik nadal znajduje się w kontenerze. - Jak wytłumaczyć tą sytuację? - Wykonaj ponownie powyższe kroki 1. i 2. - Sprawdź jakie zmiany zostały dokonane:docker diff CONTAINERID - Aby zapamiętać stan kontenera należy użyć polecenia ''docker commit'': - Przeczytaj manual do polecenia. - Zapamiętaj zmiany:docker commit CONTAINERID debian:newfile - Sprawdź jakie obrazy są teraz do dyspozycji. Czy wśród nich znajduje się właśnie wykonany commit? - Aby uruchomić kontener z obrazu stworzonego przy pomocy powyższego ''commit''-a wykonujemy następujące polecenie:docker run -ti debian:newfilePo uruchomieniu się kontenera sprawdź czy stworzony wcześniej plik nadal się w nim znajduje. ==== - Uruchamianie sortowania ==== - Sprawdzamy czy sieć wewnątrz kontenera działa. W tym celu spróbuj zaktualizować pakiety:apt-get update - Zainstalować ''git''-a:apt-get install git - Sklonować repozytorium: git clone https://github.com/fsuplicy/bubbleSort.git - Spróbować skompilować:gcc -o bubbleSort bubbleSort.cW razie braku kompilatora doinstalować odpowiednie pakiety. - Uruchomić program:./bubbleSort test_data/extralarge.txt - Można wykonać ''commit''. - Zatrzymaj kontener przy pomocy ''docker stop''. ==== - Tworzenie obrazów ==== Tworzenie swoich obrazów może być zautomatyzowane poprzez stworzenie tzw. ''Dockerfile'', pliku który zawiera wszystkie instrukcje potrzebne do osiągnięcia zamierzonego celu. Plik ten definiuje takie kwestie jak: * Obraz bazowy - na bazie którego dalsze instrukcje będą wykonywane. * Instrukcje służące do skonfigurowania środowiska. * Polecenia do uruchomienia przy tworzeniu kontenera. * Na stronie [[http://docs.docker.com/engine/reference/builder]] można przeczytać specyfikację tworzenia plików ''Dockerfile'': * Proszę szczególnie zwrócić uwagę na takie instrukcje jak: ''FROM'', ''ENV'', ''RUN'', ''ADD'', ''CMD''. - Pierwszym zadaniem będzie stworzenie pliku ''Dockerfile'', który zautomatyzuje pobieranie oraz uruchamianie programu do sortowania: - Tworzymy folder o dowolnej nazwie (''DDIR''). - W tym folderze tworzymy plik o nazwie ''Dockerfile'': - Pierwszą kwestią jaką musimy określić jest obraz bazowy. W naszym przypadku wybieramy obraz o nazwie ''debian'':FROM debian - Aby ułatwić sobie utrzymanie pliku, definiujemy kilka zmiennych przy pomocy instrukcji ''ENV'': - ''dir'' zmienna określająca nazwę folderu w którym znajduje się program ''bubbleSort''. Ustawiamy jej wartość na ''bubbleSort''. - ''exe'' nazwa pliku wykonywalnego. Ustawiamy jej wartość również na ''bubbleSort''. - ''tos'' nazwa pliku do posortowania. Wybieramy jeden plik z katalogu ''bubbleSort/test_data'' np. ''large1.txt''. - Korzystając z instrukcji ''RUN'' konfigurujemy środowisko kontenera: - Instalujemy niezbędne pakiety:# Update repositories and install dependencies RUN apt-get -y update && \ apt-get install -y gcc git - Również przy pomocy ''RUN'' wywołujemy komendę pobierającą kod z repozytorium. - Przy pomocy kolejnego wykorzystania ''RUN'' kompilujemy nasz program: # Build executables from source files RUN cd $dir && gcc *.c -o $exe - Ostatnim krokiem jest zdefiniowanie domyślnej komendy uruchamianej przy tworzeniu kontenera. W naszym przypadku uruchamiamy sortowanie wybranego pliku: # Run sorting CMD cd $dir && ./$exe test_data/$tos - Możemy teraz przystąpić do budowania naszego obrazu: - W tym celu używamy polecenia ''docker build''. - Używamy opcji ''-t'' w celu zdefiniowania nazwy i tagu naszego obrazu: - Nazwa: ''bubblesort''. - Tag: ''1.0''. - Kompletne polecenie wygląda następująco:docker build -t bubblesort:1.0 DDIRZakładamy, że wywołanie powyższej komendy odbywa się z poziomu katalogu w którym znajduje się nasz folder ''DDIR''. - Jeżeli, proces budowania zakończył się pomyślnie, to wyświetlając dostępne obrazy powinniśmy móc zobaczyć także nasz obraz:docker imagesPrzykładowy rezultat: REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE bubblesort 1.0 3677d1f27a16 23 minutes ago 309.3 MB debian newfile 1c11dae8ea4b 47 hours ago 309.3 MB ubuntu latest e9ae3c220b23 9 days ago 187.9 MB debian latest 91bac885982d 9 days ago 125.1 MB - Spróbuj teraz uruchomić stworzony obraz:docker run bubblesort:1.0Czy wyświetlane są rezultaty sortowania? - Możemy także oglądnąć historię naszego obrazu:docker history bubblesort:1.0 - Drugim zadaniem będzie rozbudowa naszego ''Dockerfile''-a o instrukcję pozwalającą na dodanie własnych plików do budowanego obrazu. - W pierwszym kroku przechodzimy do folderu ''DDIR'' i tworzymy własny plik do posortowania:CNT=10 && echo $CNT > myfile.txt && for I in `seq 1 $CNT` ; do echo $RANDOM ; done | tr '\n' ' ' >> myfile.txtWartość zmiennej ''CNT'' możemy zmieniać według upodobań. - W celu weryfikacji poprawności wygenerowanego pliku otwórz go i sprawdź czy: - Pierwsza linia to ilość liczb do posortowania. - Druga linia zawiera różne (losowe) wartości w liczbie określonej w pierwszej linii. - W pliku ''Dockerfile'' zmieniamy wartość zmiennej ''tos'' na ''myfile.txt''. - Przy pomocy instrukcji ''ADD'' dodajemy nasz plik do obrazu: - Poniższą instrukcję musimy umieścić pomiędzy kolonowaniem repozytorium a instrukcją ''CMD'':# Clone generated file to bubblesort directory ADD $tos $dir/test_data - Analogicznie jak powyżej tworzymy kolejny obraz. Tym razem naszemu obrazowi nadajemy tag ''2.0''. - Sprawdzamy czy obraz znajduje się na naszej liście. - Próbujemy stworzyć kontener i obserwujemy czy wartości w naszym pliku zostały posortowane. ==== - Zarządzanie plikami w kontenerze ==== Ostatnim zadaniem będzie skopiowanie pliku ''myfile.txt'' z uruchomionego obrazu ''bubblesort:2.0'' do uruchomionego obrazu ''bubblesort:1.0'' i posortowanie go. W tym celu wykonujemy następujące kroki: - Tworzymy dwa kontenery po jednym na podstawie każdego z utworzonych obrazów. Tym razem zamiast sortowania uruchamiamy interaktywny kontener z powłoką ''/bin/bash'': docker run -ti bubblesort:1.0 /bin/bash docker run -ti bubblesort:2.0 /bin/bash - Ponieważ kopiowanie plików pomiędzy kontenerami nie jest wspierane należy najpierw skopiować plik ''myfile.txt'' na dysk lokalny a dopiero następnie do docelowego kontenera. - Przy pomocy ''docker ps'' sprawdzamy identyfikator kontenera stworzonego z obrazu ''bubblesort:2.0''. - Wykonujemy kopiowanie przy pomocy ''docker cp''. - Analogicznie, przy pomocy ''docker ps'' sprawdzamy identyfikator kontenera stworzonego z obrazu ''bubblesort:1.0''. - Ponowanie wykonujemy kopiowanie przy pomocy ''docker cp''. - W docelowym kontenerze sprawdzamy czy nasz plik istnieje. - Jeżeli tak to próbujemy go posortować.