# Alati za razvoj softvera vežbe - O kursu: - momir_adzemovic@matf.bg.ac.rs - http://www.matf.bg.ac.rs/p/-momir-adzemovic - https://github.com/Robotmurlock/MATF-AZRA - biće kačeni snimci ## Čas 1 ### QT, QMake, QML - Potrebno je instalirati Qt Creator - Qt assistant - koristi se za dokumentaciju - Qt designer - za pravljenje UI-a - QMake i QML - Potrebno je povezati cppreference sa Qt Creator-om: - CPP Reference > dno > offline archive > qch book > zip - ekstraktujemo - QT > Tools > Options > Help > Add - samo uvek i svuda Q_OBJECT da ne razmišljaš :"D (verovatno vrlo studentski savet s Momirove strane) ![](https://i.imgur.com/fH1H0Ns.png) - U primeru sa slike, pri dodeli `A a = 2;` bi se desila implicitna konverzija na osnouv konstruktora klase `A` tj. rezultat bi bio isti kao da smo napisali `A a = A(2);`. - imaju timestamps u komentarima na YT, u suštini ono što se radi na RS iz qta podsećanje, nisam izvlačila detaljno beleške ovde ## Čas 2 ### Git (lokalno) - Obavezno pogledati [README](https://github.com/Robotmurlock/MATF-AZRS/tree/main/tema02_git). - Gde se fajlovi i izmene mogu nalaziti: ![](https://i.imgur.com/IdS15oo.png) - Prelazi: - working not modified -> working modified - dodavanje fajla, izmena postojećeg, brisanje fajla - working modified -> staging area - `git add filename` - staging area -> local repository - `git commit` - local repository -> remote repository - `git push` - remote repo -> local repo - `git fetch` - local repo -> staging area - `git reset --soft commit_hash` - staging area -> working modified - `git rm --cached filename` - `git reset filename` - staging area / working modified -> working not modified - `git checkout -- filename` - local repo -> working not modified - `git checkout commit_hash` - `git merge` - `git pull` = `git fetch` + `git merge` ![](https://i.imgur.com/dzjMcL8.png) - `git log --graph --pretty=oneline --abbrev-commit --all` ![](https://i.imgur.com/r9rfnbh.png) - `git config --global alias.ALIAS COMMAND` - definisanje aliasa, zgodno za brzo pozivanje čestih komandi ili komandi sa puno flagova koje ne želimo da pamtimo - primeri: - `git config --global alias.ci commit` - `git config --global alias.st status` - `git config --global alias.graph log --graph --pretty=oneline --abbrev-commit --all` - `git checkout HEAD~1` - skočiti na jedan commit pre heada - slično `git checkout master~1` - `git tag some_name` - obeležava poslednji (HEAD) commit sa `some_name` - može da se koristi tag da se lako skače na taj commit sa: - `git checkout some_name` - `git revert HEAD` - obriši promene iz poslednjeg commita (dodaje novi commit koji ih briše) - `git reset --hard commit_hash` - vraćamo se na označeni commit i brišemo sve promene tj. detachujemo ih i brišemo ih iz working treeja - promene se mogu povratiti ako se odmah iskoristi `git rebase commit_hash` sa hešom poslednjeg commita koji želimo da vratimo - `git commit --amend -m "commit title"` - `git mv 1.txt 2.txt` - rename (iz 1 u 2) - Branching / Grananje - razlozi za pravljenje grana: - odvojena funkcionalnost - eksperimentalna funkcionalnost - timski rad - git workflow - poštovanje plana grananja - `git branch branch_name` - pravi novu granu `branch_name` - `git branch -a` - prikazuje sve postojeće grane (remote i lokalne) - `git checkout branch_name` - premešta HEAD na kraj te druge grane - `git checkout -b branch_name` - `git branch` + `git checkout` - napravi novu granu i prebaci se na nju - `git merge branch_name` - spaja `branch_name` sa trenutnom granom preko kreiranja tzv. merge commita koji ponavlja sve diffove na celoj `branch_name` u okviru tog jednog commita na trenutnoj grani - radi dok god grane imaju zajedničkog pretka (nema veze koliko udaljenog ili razgranatog) - može da dođe do konflikta kada se naprave različite promene na istim linijama - Meld - alat za razrešavanje - uputstvo za Linux instalaciju u README na repou predmeta - Win (MINGW required): https://meldmerge.org - brisanje grana - `git branch -d branch_name` - briše granu koja je već mergeovana - `git branch -D branch_name` - briše granu koja nije spojena - Rebase - kopira granu tako da bude kao da smo branchovali od HEAD-a druge - ako smo na grani `feature`: - `git rebase master` - premešta da bude kao da smo branchovali sa poslednjeg commita na `masteru` - `git checkout master` - skačemo na `master` - `git merge feature` - mergeujemo `feature`, pri čemu to ne zahteva merge commit jer `master` nema uopšte divergentnu istoriju od `featurea`, tako da se samo "sjedine" - ako smo na grani `master`: - `git rebase feature` - svi commitovi sa `feature` grane se primenjuju na `master` od prvog zajedničkog pretka, a onda se u nastavku nadovezuju kasniji `master` commitovi - rebase menja graf / git istoriju - bezbedan je za lokalno korišćenje - **NIJE** bezbedan za promene koje su već pushovane, može se koristiti, ali onda mora da se pushuje uz argument `--force` i takođe u nekim slučajevima mora da se pulluje sa tim argumentom, inače članovi tima mogu imati divergentnu istoriju i napraviti probleme na repou - `git rebase -i branch_name` - interactive rebase - za svaki commit se bira akcija - može da se obriše linija, tad se skroz briše taj commit - mogu da se squashuju commitovi (mora bar jedan da se ostavi "na koji" će da se squashuju ostali), što znači da se spoji više commitova u jedan - ima još nekih opcija, nemam pojma piše kad odradiš komandu pa ti otvori editor - dovoljno je prvo slovo opcije staviti ispred reda za taj commit, ne mora celo ime da se piše - ima tamo u README predmeta neki git interactive rebase tool - Cherry pick - `git cherry-pick commit_hash` - uzima jedan commit sa neke grane ili odnekud i odrađuje ponovo diff urađen u njemu na trenutnoj grani (pravi novi commit) - može više heševa razvodjenih razmakom ## Čas 3 ### Git (remote) - `man git remote` - `git clone repo_path dir_name` - `git fetch` - ažurira istoriju grana sa remotea - `git pull` - `git fetch` + `git merge origin/branch_name` - `git push` - Bare repozitorijum - repozitorijum koji nema working tree, samo `.git` folder - `.git/config` - ![](https://i.imgur.com/ARfZiit.png) - može da se napravi preko `git init bare` - repo mora da bude bare da bi moglo da se pushuje na njega, jer inače nije bezbedan od konflikta koji nisu proizvod same git istorije, već lokalnih nekomitovanih promena - repo može biti remote čak i ako nije bare, ali biće read only - Gitignore - definišu se pravila kakve fajlove će da ignoriše - donekle nalik regexu - svako pravilo u novom redu - fajl mora da se zove `.gitignore` - `*` - bilo šta - `**` - bilo koji direktorijum na bilo kojoj dubini - `?` - menja jedan karakter - `[a-zA-Z]*.txt` - sve tekstualne datoteke koje počinju slovom - online generator gitignore fajlova: https://www.toptal.com/developers/gitignore - baciti pogled na dnu README na smernice za pisanje dobrih commitova ## Čas 3 ### Git Flow - dve glavne grane - master i develop - označavanje verzija: - `[GLAVNA REVIZIJA].[PODREVIZIJA].[POPRAVKA].[REVIZIJA]` - nezvanične verzije npr. alpha verzija igre često počinju sa 0, glavne verzije obično sa 1+ - ostali tipovi grana: - feature grana - pravi se iz develop, dodaje neku funkcionalnost, spaja se nazad na develop - release grana - izdvajamo verziju developa kojom smo zadovoljni i koju hoćemo da prebacimo na master, odatle se tim koji se bavi spremanjem za produkciju bavi prebacivanjem na master, dok ostali mogu da nastave razvoj na developu - hotfix - popravke direktno iz master grane, spaja se i na master i na develop - bugfix - fix za develop granu - postoji alat git flow, korsti se tako što se git komande pozivaju ovako: - `git flow init` - inicijalizuje repo sa master i develop granom - `git flow feature start feature_name` - `git flow feature finish feature_name` - `git flow release start release_name` - `git flow release finish release_name` - `git flow hotfix start hotfix_name` - `git flow hotfix finish hotfix_name` - Preskočila sam časove 4.2 i 4.3 jer kontam da su samo vežbanje, proveriti to ako ima nešto novo na njima ako nekoga zanima. ## Čas 5 ### GDB - ponovo pročitati [README](https://github.com/Robotmurlock/MATF-AZRS/tree/main/tema04_gdb), mrzi me da ovde kucam definicije baga i to - program se mora kompajlovati sa `-g` da bi GDB radio na njemu - `-g` sprečava neke kompajlerske optimizacije, što je razlog za odvojene Debug i Release verzije - [cheatsheet](https://darkdust.net/files/GDB%20Cheat%20Sheet.pdf) - Osnovno kretanje kroz program: - `run` - pokreće uvek ispočetka - `continue` - nastavlja izvršavanje - `next` - sledeća linija u trenutnoj funkciji - `step` - sledeća linija (redosledom izvršavanja, tj. ulazeći u sledeći stek okvir) - `finish` - nastavi do returna funkcije - `breakpoint` - nameštanje tačke prekida - `clear` - briše sve breakpoints - Ispis: - `print var_name` - `display var_name` - `undisplay display_id` - Stek okviri: - `backtrace` / `bt` - izlistava sve stek okvire - `backtrace 5` - poslednjih 5 samo - `where` radi isto što i `backtrace` - `up` - idemo unazad kroz stack - može da primi brojčani argument za koliko frejmova da se pomeri (npr. `up 2`) - `down` - suprotno - isto za br. arg - `frame num` - skače na frejm označen brojem `num` - štampa frame number, ime funkcije, argumente, ime izvornog fajla, broj te linije u tom okviru, kao i celu liniju izvornog koda (ovo radi i kad je navedemo bez argumenata za trenutni okvir) - Praćenje vrednosti promenljivih: - `watch var_name` - javlja kad god se promeni vrednost zadate promenljive - `delate` / `disable` / `enable` - može da se uključuje/isključuje watchpoint - `whatis var_name` - vraća tip promenljive - `info` - može razne informacije da daje - npr. `info args` vraća argumente funkcije (u kojoj smo trenunto) - `info breakpoins` - `info display` - `info locals` - LLDB - debager u okviru LLVM projekta ## Čas 6 ### CMake - opensource - ima svoj interpretirani imperativni jezik za pisanje skripti - omogućava da se proces prevođenja apstrahuje u odnosu na platformu na kojoj se prevodi - `CMakeLists.txt` - podrazumevani fajl u koji idu uputstva za prevođenje - Struktura CMake fajla i razne komande: - `cmake_minimum_required(VERSION 3.16.3)` - minimalna verzija CMake da bi mogla da se kompajluje skripta - moguće proveriti instaliranu verziju sa `cmake --version` - optimalno bi bilo proveriti sve funkcionalnosti kada su izašle i uzeti najveću neophodnu verziju - `project(HelloWorld VERSION 1.0.0)` - definišemo ime i verziju projekta - uz dodeljivanje imena i verzije projektu, definiše i neke podrazumevane promenljive koje posle mogu da se koriste u CMake, npr. `PROJECT_NAME` - `add_executable(executableName fileName.cpp)` - `CMakeLists.txt` za Hello World program: - ![](https://i.imgur.com/ii6vbEN.png) - možemo da napravimo podfolder `build` u koji će ići relevantni fajlovi tokom kompilacije, da se ne zatrpava širom projekta - ``` mkdir build cd build/ cmake -G "Unix Makefiles" .. make ``` - zgodno je za gitignore zato što možemo da stavimo samo ceo build folder - `make help` - prikazuje sve opcije sa Makefileom koji je CMake generisao, postoje razne stvari tipa za clean, kompajlovanje do asemblera, i sl. - ``` add_library( <libName> [STATIC|SHARED|MODULE] <source1> <source2> ... ) ``` - `<libName>` je ime biblioteke koju dodajemo - `<sourceX>` su izvorni kodovi koji pripadaju toj biblioteci - oznake `STATIC`, `SHARED`, `MODULE`... - `STATIC` - podrazumevano, kod biblioteke se bukvalno kopira, kod se duplira - `SHARED` - ne kopira se, nego se vrši referenciranje na delove biblioteke koji su nam potrebni, dobro je za dinamičko povezivanje biblioteka - `MODULE` - nije objasnio - `target_link_libraries(executableName PRIVATE libName)` - linkuje biblioteku i executable - mogu da se prave `CMakeLists.txt` fajlovi u podfolderima i da se svi includeuju u glavni - korisno jer ne moramo da pratimo relativne putanje biblioteka, već ako se promeni menjamo samo lokaciju jednog CMakeLists.txt - `add_subdirectory(dirName)` - u glavnom CMake povezujemo podfolder - ako se učitava više poddirektorijuma koji imaju međusobnu zavisnost, redosled učitavanja mora da poštuje tu zavisnost - `target_include_directories(dirName PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")` - u datoteci u podfolderu povezujemo glavni CMake fajl iz nadfoldera - `PUBLIC` / `PRIVATE` / `INTERFACE` - svaka od ovih dopunjava neke liste potrebne CMakeu za rad - ima u dokumentaciji, ali komplikovani su detalji oko ovoga, "nećemo mnogo da se zadržavamo na tome za sada" - `cmake --configure .` - prevođenje skripte - CMake jezik i sintaksa: - jednostavan interpretirani jezik - radi sa funkcijama, niskama, nizovima... - sve su implicitno niske - uključujući i imena promenljivih - svaka komanda je sledećeg oblika: - `command (<arg1> <arg2> ... <argK>)` - svaka funkcija prima neograničeno argumenata (spaja niske koje su višak u jednu) - komentari počinju sa `#` - promenljive i poruke - `message("This is my message!")` - `message(STATUS "This is my message!")` - `message(One Two Three)` - rezultat: `OneTwoThree` - `message("One Two Three")` - rezultat: `One Two Three` - `message("Project name is ${PROJECT_NAME}")` - neke komande implicitno definišu promenljive, npr. `project` implicitno definiše `PROJECT_NAME` - `set(<name> <expression>)` - `set(MY_VAR "[1, 2, 3, 4, 5]")` - `message("MY_VAR = ${MY_VAR}")` - rezultat: `MY_VAR = [1, 2, 3, 4, 5]` - kontrola toka - istinitosne vrednosti: - niska je tačna ako se nalazi na listi niski koje imaju netačnu vrednost u dokumentaciji (case insensitive), npr: - `TRUE` - `1` - `ON` - `YES` - `Y` - niska je netačna ako se nalazi na listi niski koje imaju netačnu vrednost u dokumentaciji (case insensitive), npr: - `FALSE` - `NOTFOUND` - `0` - `OFF` - `NO` - `N` - `IGNORE` - prazan string - završava se sufiksom `-NOTFOUND` - sve ostale niske su promenljive, a sve promenljive van spiska iz dokumentacije su truthy - ``` if( "TRUE" ) # ... elseif( "FALSE" ) # ... else() # ... endif() ``` - operacije koje daju istinitosne vrednosti: - logičke: `AND`, `OR`, `NOT` - poređenje: `EQUAL`, `LESS`, `GREATER` - string poređenje: `STREQUAL`, `STRLESS`, `STRGREATER` - `MATCHES` - za regex - rad s fajlovima: `IS_NEWER_THAN`, `IS_DIRECTORY`, `IS_SYMLINK`, `IS_ABSOLUTE` - verzije: `VERSION_LESS`, `VERSION_EQUAL`, `VERSION_EQUAL` - `DEFINED` - istinito ako je promenljiva definisana - petlje: - ``` set(cnt 0) while(cnt LESS 10) message("Counter value is ${cnt}") math(EXPR cnt "${cnt}+1") endwhile() ``` - ``` foreach(i RANGE 100) message("${i}") endforeach() ``` - ``` foreach(item IN ITEMS apple orange peach banana) message("${item}") endforeach() ``` - funkcije: - ``` function(<name> <arg1> <arg2> ... <argK>) # ... endfunction() ``` - ``` function(printmsg msg) message(${${msg}}) # dereference once to get PROJECT_NAME out of msg # dereference second time to get value of PROJECT_NAME endfunction() printmsg(PROJECT_NAME) ``` - funkcija sa povratnom vrednošću - ``` function(incrementvar var) math(EXPR new_value "${${var}} + 1") set(${var} ${new_value} PARENT_SCOPE) endfunction() set(value 10) increment(value) message("Result is ${value}.") ``` ### Arrange - Act - Assert - metod testiranja softvera - Arrange - deklaracija i inicijalizacija svega potrebnog - Act - primena funkcija koje želimo da testiramo - Assert - provera povratnih vrednosti - `#include <cassert>` - biblioteka uz pomoć koje smo radili primer ovoga - `assert(bool_expr);` - komanda za proveru ## Čas 7 ### Valgrind - profajler - debager - sadrži više alata - `valgrind [options] main.out` - kad prevodimo program koji hoćemo da pokrenemo preko Valgrinda, treba da kompajlujemo sa `-g` ako hoćemo da Valgrind može da nam prijavi stvari tipa na kojoj liniji je alocirano nešto što kasnije nije oslobođeno tj. curi ili bilo koje slične informacije koje se izgube tokom kompilacije i optimizacija #### Memcheck - služi za otkrivanje curenja memorije u programu - `valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all --track-origins=yes --log-file=log.txt ./main.out` - `--tool` - podrazumevano je memcheck, ovde je ispisano eksplicitno ali ne mora - `--leak-check=full` - ispisuje detalje za svako curenje memorije - `--show-leak-kinds=all` - ispisuje sva moguća curenja (uključujući i neka potencijalna koja nisu sigurna, koje nalazi preko nekih heuristika) - `--track-origins=yes` - ispisuje gde je nastalo curenje - `--log-file=log.txt` - ispisuje u log fajl, jako bitno - u suštini bitno samo ovo staviti, ostalo iskopati u man stranama ako nam treba - primer curenja: - ![](https://i.imgur.com/4x01tMe.png) - primer curenja kad se uključi `-g` pri kompilaciji: - ![](https://i.imgur.com/SZ8DLzO.png) - RAII - resource acquisition is initialization - konstruktor nabavlja resurs, a destruktor ga oslobađa - postoji sličan tool Memchecku koji se zove heapcheck koji se odvojeno instalira i kao je efikasniji i nzm ni ja, nismo ga radili ali je napomenuo ako nekome zatreba #### Helgrind - služi za pronalaženje grešaka i predikciju grešaka pri radu sa nitima - kad radimo s nitima ne zaboravimo `-lpthread` flag - `valgrind --tool=helgrind --log-file=log.txt ./main.out` - kako prijavljuje problem: - ![](https://i.imgur.com/tKSrnSk.png) - trka za resurse: - bar jednom resursu pristupa više niti - barem jedna nit piše - ne postoji međusobno isključivanje - pored očiglednih izvora trke za resurse, može se desiti i oko output streamova, uključujući i std::cout - ``` #include <mutex> std::mutex mutex; ... mutex.lock(); // sensitive code mutex.unlock(); ``` - druga opcija, zaključavanje celog bloka koda: - `const std::lock_guard<std::mutex> lock(mutex);` - nešto kao `synchronized` u Javi - treća opcija, atomic promenljive - ``` #include <atomic> ... std::atomic<int> result(0); ``` - ovako inicijalizovana promenljiva može bezbedno višenitno da se koristi bez ikakvog dodatnog podešavanja, ali promenljiva mora da se menja [specijalnim funkcijama](https://en.cppreference.com/w/cpp/atomic/atomic/fetch_add) umesto osnovnih operacija #### Callgrind i KCachegrind - alat za profajliranje - `valgrind --tool=callgrind --callgrind-out-file=callgrind.out ./main.out` - `kcachegrind callgrind.out` - namestiti No grouping ovde: - ![](https://i.imgur.com/nCgzP5F.png) - Može i Source file da se ostavi ako hoćemo da gledamo samo iz maina ili odakle već - bitna je opcija Relative to Parent - ![](https://i.imgur.com/r33PhPD.png) - prikazivanje grafa poziva: - ![](https://i.imgur.com/hFprauX.png) - desni klik na graf pa ima export graph as image - ![](https://i.imgur.com/5zNLiLd.png) - distance je dužina najkraćeg puta u grafu #### Gammaray - inspekcija qt aplikacija - prikači se "kao neki parazit" za qt aplikaciju i hvata i prikazuje koji se signali šalju i slično - može da prati stanja qt state machine - pokretanje iz terminala: - `gammaray` - pokretanje iz qt: - `Tools>External>KDAB` ako je već podešeno - ako nije podešeno: - `Tools>External>Configure` - `Add` dodati kategoriju i nazvati `KDAB` - `Add` dodati tool , description `Gammaray`, executable ukucamo `whereis gammaray` u terminalu i kopiramo šta nam kaže - šta imamo sve: - Events - Types - mogu da se isključe događaji da se ne prikazuju u logu, npr. MouseMove, MouseHover, i slični događaji koji se baš puno dešavaju i zatrpavaju sve ostalo - možemo da kliknemo na događaj da vidimo informacije o signalu koji je pokrenuo događaj - Meta Objects - možemo dinamički da postavimo koji su objekti aktivni, gledamo njihove tipove i atribute - npr. nađemo Button, možemo da vidimo Properties, Methods... - Meta Type - prikazuje koliko memorije koji objekat zauzima - Objects - aktivni UI objekti - možemo da pratimo njihova stanja - Connections - koji su slotovi povezani - Resources - koje sve resurse koristi - Widgets - može kad selektujemo nešto da označi šta je to zapravo u prozoru - može tuda direktno da se interaguje sa aplikacijom preko gammaraya - može da se zabeleži action order kao strelice na slici - ![](https://i.imgur.com/XH7t3tF.png) #### Korišćenje gita preko qt - ovo sam preskočila ## Čas 8 ### Clang alati - deo LLVM projekta #### Clang Tidy - za refaktorisanje C++ koda, može ponekad statički da nađe curenje memorije - ovakvi alati se nazivaju linteri - koristan za prevođenje koda na novi standard - `clang-tidy filename [options]` - `clang-tidy --checks-* --fix -- --std=c++17 > log.txt 2> error.txt` - `--checks=*` - koristi sve provere - `--checks=*,-modernize-*` - koristi sve provere osim modernize - `--checks=modernize-use-nullptr` - pretvara `NULL` u `nullptr` - `--checks=modernize-use-using` - menja typedef sa using - `--checks=readability-container-size-empty` menja `smth.size()==0` sa `smth.empty()` - `--checks=readability-identifier-naming` - enforces coding guidelines on identifier naming - treba podesiti u `.clang-tidy` fajlu standarde - `--checks=performance-implicit-conversion-in-loop` - menja tipove u petljama da izbegne implicitne konverzije - `--checks=performance-inefficient-string-concatenation` - ovo samo analizira, moramo ručno da ispravimo - `--checks=llvm-namespace-comment` - dodaje komentar na kraju namespacea sa imenom namespacea - gledati da uključimo samo šta nam treba jer zna čudno da se ponaša, više puta da vrši promene, da radi neke konfliktne promene, napravi da ne može više da se kompajluje, razne paklove, ugl ne pokretati tek tako sa `*` jer ko zna šta će da uradi - `--fix` - zapravo menja datoteku, sređuje - `--` - desno od ovoga idu kompilacione opcije - preporuka: uvek sačuvati pre korišćenja clanga preko gita ili kopirati projekat, zna nekad da uradi neke gluposti (tipa više procesa nađe istu grešku i onda triput dopiše isti keyword) - `cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..` - pokrećemo ovako da bismo dobili `compile_commands.json` fajl - `run-clang-tidy` - neka inbuilt py skripta nešto? - `run-clang-tidy -checks='modernize-*' -fix` #### ClangFormat - formatira kod za nas - stilove biramo opcijom `--style=[STYLE]` - `man clang-format` ima spisak inbuilt stilova - `clang-format --style=LLVM main.cpp` - primer primene - `clang-format --style=LLVM -i main.cpp` - `-i` - in-place izmena - `clang-format --style=LLVM main.cpp > main.cpp` - preusmeren output na sam main.cpp ## Čas 10 ### Docker - omogućava isporuku aplikacija u okviru kontejnera - ideja je da zapakujemo sve zavisnosti u jednu jedinicu (kontejner) - ovo omogućava da pouzdano pokrenemo aplikaciju na više okruženja, jer suštinski simuliramo okruženje u kom znamo da radi - OS-level virtualization - na Linuxu definitivno - na Windowsu nisam sigurna da li je čisto OS nivo - Docker container image je samostalan paket softvera koji sadrži: - kod - okruženje - sistemske alate - biblioteke - opcije - ![](https://i.imgur.com/0ow8zNz.png) - VM vs kontejner - kontejner: - spaja kod naše aplikacije i njegove zavisnosti u jedno (i VM to radi, ali ne u istom smislu, kontejner može da pokrene direktno samu aplikaciju sa svim zavisnostima, dok VM pokreće OS u okviru kog onda možemo da otvorimo app, a možemo da radimo i druge stvari) - više kontejnera mogu biti u okviru jednog OSa i mogu čak deliti jezgro (kernel) - znatno manji od VM - brzo se pokreću - VM: - apstrakcija na nivou hardvera - Hypervisor dopušta da se više pokreće istovremeno - svaka ima svoju kopiju OS - sporo se pokreću - ![](https://i.imgur.com/eqPJbxv.png) - Prednosti dockera - pojednostavljavanje konfiguracije kontejnera - dobar za deployment - Multi-tenant aplikacije - na serveru se pokreće kontejner za svakog klijenta npr. - produktivnost razvijaoca - manje čekanje na pokretanje svaki put tokom rada i testiranja - konsolidacija servera - jeftinije raditi sa kontejnerima nego VM - lak debug - brz izvoz - fajl za konfiguraciju dockera se zove `Dockerfile` - ``` FROM gcc:latest COPY . /usr/src/hello-world WORKDIR /usr/src/hello-world RUN g++ -o hello-world main.cpp CMD ["./hello-world"] ``` - `FROM [image]` - slika na kojoj baziramo svoju - preporuka `ubuntu:16.04`, na času mu nije radio `apt-get install -y python-pip` za ubuntu:20 - `COPY` - kopiramo - `.` - iz trenutne putanje na lokalnoj mašini - `/usr/src/hello-world` - u ovaj folder u okviru kontejnera - `WORKDIR /usr/src/hello-world` - namestimo ovo na radni direktorijum - `RUN [command]` - pokreće komandu - ovo je pripremna faza slike - bilo šta što zahteva input pri instalaciji ili slično mora da ga dobije nekako kroz komandu inače će zakočiti na tome, ako je jedna od onih stvari što pita yes/no na Linuxu radi argument `-y` - `CMD ["./hello-world"]` - kad se svo predpodešavanje pre ovoga završi, pokreće se ova komanda. Kada program pokrenut ovom komandom prestane da radi, gasi se ceo kontejner - može i `CMD ./hello-world` bez navodnika i toga - Kad smo napisali `Dockerfile` treba da ga prevedemo u sliku - `docker build -t hello-world .` - `-t` - zadajemo ime slike nakon ovoga - može na ime da se doda tag, npr. `hello-world:1.0.0` - `.` - lokacija gde nam je `Dockerfile` - ako se pokreće build više puta jer je fejlovao prošli put ili je izmenjen, pokrenuće prvi neuspeli ili izmenjeni korak, a ovo pre toga neće opet raditi, tako da ako smo čekali neku dugačku instalaciju prvi put nećemo morati ponovo ako je ona bila pre dela koji smo izmenili - `docker image ls` - pregledamo sve slike na sistemu - `docker run --name helloworld hello-world:latest` - nakon što je kontejner pokrenut jednom, ne možemo da ga pokrenemo ponovo pod istim imenom, nego mora ili da se obriše ili preimennuje - može da se doda `-e ENVIRON_VAR_NAME=value` - `docker inspect value | grep ENVIRON_VAR_NAME` da nađemo posle - možemo i da napravimo `env.txt` pa umesto `-e` ide: - `--env-file env.txt` - `docker ps` - izbacuje sve kontejnere koji trenutno rade nešto - može da se doda flag `-a` da se vide prethodno pokrentui kontejneri (i oni koji su završili izvršavanje) - `docker rm helloworld` - briše helloworld kontejner - `docker rm $(docker ps -aq)` - briše sve kontejnere - `docker rmi hello-world` - remove image - docker hub - `docker pull image-name` - `docker login --username=your_username` - `docker tag hello-world:latest your_username/helloworld:2.0` - `docker push your_username/helloworld` - radi rmi i za remote sliku, ali briše se samo lokalno - `docker run --name container-name image-name` - implicitno će probati da nađe na hubu ako ne nađe lokalno - port mapping - svaki kontejner ima svoj IP i svoj interni port, mi možemo to da povežemo sa portom na localhostu - u okviru komande `docker run`: - `-p 5005:5000` - levi broj - port na localhostu - desni broj - port unutar kontejnera - nakon što smo pokrenuli ovako, možemo da otvorimo kao localhost:5005 - ``` FROM gcc:latest COPY . /usr/src/hello-world WORKDIR /usr/src/hello-world RUN g++ -o hello-world main.cpp ENTRYPOINT ["./hello"] CMD ["5"] ``` - ENTRYPOINT je uvek na početku komande u terminalu - CMD je sufiks posle toga, ali ako navedemo argument pri pokretanju on neće biti naveden - primer: - `docker run blabla ./hello` - pokreće hello s argumentom komandne linije 5 - `docker run blabla ./hello 3` - pokreće hello s argumentom komandne linije 3 - možemo da zamenimo i entrypoint pri pokretanju - `docker run --entrypoint [NEW_ENTRYPOINT] blabla` - možemo da spojimo kontejner s nečim van kontejnera, tipa nekom bazom ili drugačijim pohranjivanjem podataka na localhostu da ne bismo pri padu servera izgubili ceo sadržaj containera - `docker run -v ~data_volume:/data database` - `~/data_volume:/data` - `~/data_volume:` - putanja lokalno - ako ne dodamo `~` onda neće biti na putanji u sistemu, nego u Dockerovom folderu koji onda može da se koristi za komunikaciju između kontejnera - da bi ovo radilo mora prvo da se pokrene: - `docker volume create data_volume` - `/data` - putanja u kontejneru - time smo povezali kontejner sa lokalnim OSom i sve promene iz datog foldera (data) će se kopirati i na naš sistem ## Čas 11 ### Docker - Advanced - MySQL - `--detach` na run da se pokrene odvojeno od instance terminala - može `-d` - `--publish 6603:3306` - isto kao `-p` - `--volume=/root/docker/simple-mysql-server-db/conf.d:/etc/mysql/conf.d` - isto kao `-v` - opcija za pokretanje kontejnera sve dok ne uspe? - `docker-compose.yml` - služi za prevođenje i pokretanje više kontejnera odjednom - ``` version: '3' services: mysql-server-db: image: mysql environment: - MYSQL_ROOT_PASSWORD=Root_12345 ports: - 10001:3306 volumes: - /root/docker/mysql-server-db/conf.d:/etc/mysql/conf.d flask-server: build: ./server network_mode: host restart: on-failure ``` - `build: ./server` je putanja do direktorijuma u kome se nalazi `Dockerfile` za pravljenje ove slike - `restart: on-failure` - jer će pucati dok se ne podigne mysql baza da bi mogao da se konektuje na nju - `docker compose up --build`