Node starter projekat (TypeScript + Docker)

Kostur projekta

Pretpostavićemo da će projekat imati više manjih projekata tj. kontejnera, npr. deo za mikroservise, deo za rad sa bazom… Te je dobro da se u root-u projekta naprave podfolderi za svaki manji projekat npr.:

node_project/
├── api/        # Ovaj za mikroservise
├── data/       # Ovaj folder za bazu podataka

Kreiranje package.json

Prvo ćemo kreirati package.json fajl u root folderu projekta. Ovaj fajl će sadržati sve potrebne informacije o projektu, kao što su naziv, verzija, zavisnosti… Za kreiranje osnovne verzije package.json koristićemo npm init naredbu sa flagom “YES” “-y” da sve sam popuni bez pitanja:

cd api
npm init -y

Nakon toga će package.json fajl izgledati ovako:

{
  "name": "api",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

Za dalji rad je potrebno da kreiramo i definišemo početni JS fajl. Početni JS fajl ćemo krerati u sklopu “src” foldera kojeg ćemo smestiti u okviru “api” foldera (npr. app.js). Nakon toga je potrebno da prepravimo lokaciju i ime početnog fajla u sklopu package.json-a:

"main": "src/app.js"

Typscript podrška

  1. TypeScript

    Prvo je potrebno da instaliramo sam TypeScript:

    npm install typescript --save-dev
  2. tsconfig.json

    tsconfig.json fajl se koristi za konfiguraciju TypeScript kompajlera (tsc). Služi za definisanje različitih opcija kompajliranja koje upravljaju načinom na koji će TypeScript kod biti preveden u JavaScript. Ovaj fajl možete da inicijalizujete naredbom

    npx tsc --init
    Primer
    {
        "compilerOptions": {
          "target": "ES6",                                  // Ciljni ECMAScript standard
          "module": "commonjs",                             // Modul sistem koji se koristi
          "strict": true,                                   // Omogućava striktan mod
          "esModuleInterop": true,                          // Pomaže u interoperabilnosti sa ECMAScript modula
          "skipLibCheck": true,                             // Preskače proveru tipova u fajlovima definicija
          "outDir": "./dist",                               // Izlazni direktorijum za kompajlirane fajlove
          "rootDir": "./src",                               // Korenski direktorijum za ulazne fajlove
          "resolveJsonModule": true,                        // Omogućava import JSON fajlova kao module
          "sourceMap": true,                                // Generiše sourcemap fajlove
          "noImplicitAny": true,                            // Onemogućava neizričit "any" tip
          "moduleResolution": "node",                       // Modul rezolucija strategija koja se koristi
          "baseUrl": ".",                                   // Osnovna putanja za rezoluciju modula
          "paths": {                                        // Mape za rezoluciju modula
            "@app/*": ["src/app/*"],
            "@config/*": ["src/config/*"]
          }
        },
        "include": ["src"],                                 // Direktorijumi/fajlovi koji se uključuju u kompajliranje
        "exclude": ["node_modules", "dist", "test"]         // Direktorijumi/fajlovi koji se isključuju iz kompajliranja
      }
  3. ts-node

    Da bi pokrenuli TypeScript direktno iz Node okruženja bez potrebe za prethodnim kompajliranjem u JS, potrebno je instalirati ts-node paket:

    npm install ts-node --save-dev

    Zatim kreiramo jednostavnu “start” skriptu za pokretanje aplikacije u produkciji:

    "scripts": {
        "start": "ts-node src/app.ts"
    }

    Pozivanjem naredbe iz terminala se pokreće aplikacija:

    npm start
  4. @types paketi

    Kada koristiš JavaScript biblioteke u TypeScript projektu, onda je potrebno da instaliraš odgovarajuće tipove kako bi otklonio greške na nivou kompajlacije. JavaScript-u je dinamički tipiziran jezik, što znači da nema ugrađene tipove a da bi TypeScript znao koje bi tipove trebo koristi za Node.js (pisan u JS-u), moramo listu tih definicija a koje možemo naći u paketu @types/node.

    npm install @types/node --save-dev

    Ako npr. koristimo “fs” modul, bez @types/node paketa, TypeScript kompajler ne bi znao ništa o njemu, što bi dovelo do grešaka tokom kompajlacije. Isto važi i za Express, TypeScript ne zna koje bi tipove trebao da koristi za promenjive pisane u Express-u, te je potrebno da mu pomognemo da ne bi izbacivao greške pri kompajliranju tako što ćemo instalirati paket @types/express

    npm install @types/express --save-dev
  5. Nodemon

    Nodemon paket nam omogućava automatski restart aplikaciju na serveru kada detektuje promene u datotekama u projektu, a instalira se na sledeći način:

    npm install --save-dev nodemon

Definisanje skripti

Ako imamo instaliran nodemon paket onda možemo da kreiramo skriptu sa kojom ćemo restartovati server svaki put ukoliko dodje do promene koda. Ta skripta se obično naziva “dev” jer se koristi u lokalu pri developmentu:

"scripts": {
    dev": "nodemon --watch src --exec ts-node src/app.ts"
}

Ova skripta se poziva iz terminala na sledeći način:.

npm run dev

Nakon startovanja skripte nodemon prati promene u fajlovima unutar src direktorijuma i ako ih primeti nakong toga automatski ponovo pokreće src/app.ts fajl koristeći ts-node biblioteku, kompajlirajući TypeScript kod “u letu”.

NAPOMENA:
Za bildovanje JS projekta možemo kreirati i skriptu npr. "build": "tsc". Ova komanda će pokrenuti TypeScript kompajler koji će prevesti sve .ts fajlove u .js fajlove prema konfiguraciji definisanoj u tsconfig.json fajlu i smestiti ih u izlazni direktorijum (obično dist ili build). Skripta se poziva na sledeći način:.

npm run build

ENV promenjive

U node.js okruženju kao i u drugim sistemima se koriste promenjive okruženja okupljene u jedan fajl, sa čijim korišćenjem se izbegavaju hardkodirani podaci razbacani po izvornom kod-u na različitim mestima, taj fajl se obeležava sa .env i kreiramo ga u root folderu projekta. Pa će struktura projekta izgledati ovako:

node_project/
├── api/
│   ├── src/
│   │   └── app.ts
│   ├── .env
│   ├── package.json

Za učitavanje (environment) promenljivih iz .env fajla u process.env je potrebno da instaliramo dotenv paket:

npm install dotenv

Potrebno je na početku izvršavanja koda (npr. u početnom fajlu) da se pozove metoda config() iz DotEnv paketa jer ona učitava sadržaj .env datoteke i dodaje svaku promenljivu u “process.env”objekat. Više o env promenjivama pročitajte u članku Promenjive okruženja.

NAPOMENA:
.env datoteku treba dodati u .gitignore fajl kako bi se izbeglo njeno deljenje sa verzionim kontrolama, čime se štite osetljive informacije. Obratite pažnju da se u produkciji ne zaboravi da se “ručno” napravi novi .env fajl jer se on ne šalje sa git-om !!!

Dockerizacija

Dockerfile

Dockerfile je tekstualna datoteka koja sadrži uputstva za kreiranje Docker slike (eng. image). Dockerfile sadrži niz uputstava (instrukcija) koje određuju kako će Docker slika biti kreirana.

# Osnova slika za kontejner preuzima se iz DockerHub-a
FROM node:20-alpine

# Setujemo radni direktorijum u kontejneru
WORKDIR /user/src/app

# Kopiramo package.json i package-lock.json u radni direktorijum   
# (./ je radni direktorijum tj. app)
COPY package*.json ./

# Instaliramo zavisnosti iz package.json fajla samo kada je produkcija 
# koristeći "clean install" (npm ci) koji prvo obriše node_modules folder
RUN npm ci --only=production

# Kopiramo sve fajlove iz trenutnog direktorijuma u radni direktorijum
COPY . .

CMD [ "npm", "run", "dev" ]

Više o Docker-u i njegovom korišćenju pročitajte u članku “Docker: Pokretanje aplikacija svuda”

docker

Kreiranje slike (“build”)

Za kreiranje Docker image-a iz Dockerfile-a se koristi komanda docker “build”. Ova komanda ima nekoliko opcija koje omogućavaju prilagođavanje procesa build-ovanja. Detaljno objašnjenje opcija koje se često koriste sa komandom docker build je sledeće:

docker build [OPTIONS] PATH | URL | -

Gde je PATH direktorijum koji sadrži Dockerfile, URL može biti URL ka GIT repozitorijumu, a “-“ omogućava čitanje Dockerfile-a iz standardnog ulaza. Evo liste nekih opcija:

  • –tag skraćeno -t: Oznaka za image. Omogućava imenovanje image-a i dodeljivanje verzije (tag-a).
    docker build -t my-image:latest .
  • –file skraćeno -f: Specifikuje putanju do Dockerfile-a ako nije u trenutnom direktorijumu.
    docker build -f /path/to/Dockerfile .
  • –build-arg: Prolaz promenljive kao build argument. Ove promenljive se mogu koristiti unutar Dockerfile-a.
    docker build --build-arg HTTP_PROXY=http://proxy.example.com .
  • –no-cache: Onemogućava korišćenje keša za build, osiguravajući da se svaki sloj ponovo izgradi.
    docker build --no-cache -t my-image:latest .
  • –pull: Uvek povlači najnoviji osnovni image pre build-ovanja.
    docker build --pull -t my-image:latest .
  • –label: Dodaje metapodatke (label-e) image-u.
    docker build --label version="1.0" --label maintainer="[email protected]" .

NAPOMENA:
Kada Docker gradi image, potrebno mu je da ima pristup svim fajlovima koji su navedeni ili korišćeni unutar Dockerfile-a. Ovi fajlovi se nalaze u direktorijumu koji se naziva “kontekstualni direktorijum”. Tačka (“.”) na kraju komande docker build jednostavno znači “koristi trenutni direktorijum kao kontekstualni direktorijum”. To omogućava Docker-u da pročita Dockerfile i sve potrebne resurse iz tog direktorijuma kako bi kreirao image.
Primer:
Tačka (.) u naredbi docker build -f /path/to/Dockerfile . označava trenutni direktorijum kao kontekstualni direktorijum. To znači da Docker koristi sve fajlove iz tog direktorijuma u procesu build-ovanja, dok Dockerfile može biti specificiran bilo gde u sistemu pomoću -f opcije.

Primer
docker build -t my-image:1.0 -f /path/to/Dockerfile --build-arg HTTP_PROXY=http://proxy.example.com --no-cache --pull --label version="1.0" --label maintainer="[email protected]" .

Ova komanda će:

  • Kreirati image pod nazivom my-image sa tag-om (verzijom slike) 1.0
  • Korisiti Dockerfile iz specificiranog puta
  • Postaviti build argument HTTP_PROXY
  • Izvršiti build bez korišćenja keša
  • Uvek povući najnoviji osnovni image
  • Dodati dve oznake (label-e) image-u
  • Kontekstualni direktorijum je trenutni direktorijum

Pre pokretanja naredbe “build” u Windows-u je potrebno da startujemo Docker desktop aplikaciju i poželjno je da u terminalu budete u root-u projekta u kome se nalazi i Dockerfile.
Nakon izvršene komande možete da proverite u “Docker deskop” aplikaciji image, ali to isto možete uraditi i kroz terminal naredbom:

docker images

Docker skripte

Ako želimo da ubrzamo rad sa Dockerom, možemo da pripremimo skripte u package.json kao npr.

"docker:build": "docker build -t starter_node:latest .",
"docker:run": "docker run --name node_api starter_node:latest",
"docker:stop": "docker stop node_api && docker container prune -f"

Objašnjen

  1. Skripta docker:build kreira Docker sliku iz Dockerfile-a, pos imenonm “starter_node:latest”
  2. Skripta docker:run pokreće novi kontejner, dodeljuje mu ime “node_api” na osnovu slike “starter_node”
  3. Skripta docker:stop zaustavlja kontejner sa imenom “node_api”, zatim uklanja sve zaustavljene kontejnera bez traženja potvrde

Više o docker naredbama pogledajte u članku Docker: Pokretanje aplikacija svuda

REZIME

Ovako izgleda struktura projekta:

node_project/
├── api/
│   ├── src/
│   │   └── app.ts
│   ├── dist/
│   │   └── app.js
│   ├── .env
│   ├── package.json
│   └── Dockerfile
├── data/  # Ovaj folder za bazu podataka

A ovako package.json fajl:

{
  "name": "api",
  "version": "1.0.0",
  "description": "",
  "main": "src/app.ts",
  "scripts": {
    "start": "ts-node src/app.ts --env-file=.env.production",
    "build": "tsc",
    "dev": "nodemon --watch src --exec ts-node src/app.ts --env-file=.env.development",
    "docker:build": "docker build -t starter_node:latest .",
    "docker:run": "docker run --name node_api starter_node:latest",
    "docker:stop": "docker stop node_api && docker container prune -f"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "dotenv": "^16.4.5",
    "express": "^4.19.2",
    "nodemon": "^3.1.0"
  },
  "devDependencies": {
    "@types/express": "^4.17.21",
    "@types/node": "^20.12.12",
    "ts-node": "^10.9.2",
    "typescript": "^5.4.5"
  }
}

Pogledajte ceo kod startnog projekta na GitHub-u https://github.com/choslee/node_typescript_doceker_starter


Docker: Pokretanje aplikacija svuda


Uvod u Docker svet

Šta je Docker?

Docker je platforma koja omogućava programerima da jednostavno kreiraju, implementiraju i pokreću aplikacije unutar kontejnera.

Šta su to kontejneri?
Kontejneri se mogu shvatiti kao lagane virtuelne mašine, ali su dosta brži i manje zahtevni od njih, oni sadrže sve što je potrebno za pokretanje aplikacije: kod, biblioteke i podešavanja operativnog sisteme.

docker image

Zašto koristiti Docker?

  1. Rad aplikacije na različitim sistemima

    Kada aplikacija radi u kontejneru, onda ona može raditi bilo gde, i lokalno ili u nekom udaljenom serveru. Kontejneri omogućavaju aplikacijama da rade konzistentno u različitim okruženjima a to se naručito “oseti” kod timova koji razvijaju aplikaciju na različitim računarima koristeći različite operativne sisteme, kao npr.:

    • Programer A (Windows): Razvija aplikaciju u Docker kontejneru.
    • Programer B (Mac): Testira aplikaciju u Docker kontejneru.
    • Server za produkciju (Linux): Pokreće aplikaciju u istom Docker kontejneru.

    Bez Docker-a, svaki programer bi morao instalirati sve potrebne alate i biblioteke na svom računaru, što može dovesti do problema sa kompatibilnošću i reproduktivnošću. A ako se koristi Docker onda svi programeri koriste jednu istu Docker sliku, što im omogućava da razvijaju i testiraju aplikaciju u identičnom okruženju. Na kraju, aplikacija se prenosi na produkciju bez brige o različitim verzijama biblioteka ili softvera na produkciskom serveru.

  2. Izolacija aplikacije

    Kontejneri omogućavaju svakoj aplikaciji da radi u svom odvojenom okruženju, bez međusobnog ometanja. Ovo može biti veoma bitno kod kompanija koja razvijaju ili hostuje dve različite aplikacije a koje zahtevaju različite verzije MySQL baze podataka. U tom slučaju je idealno da se koristi Docker jer se tada svaka aplikacija može smestiti u svoj Docker kontejner sa odgovarajućom verzijom MySQL-a, kao u sledećem primeru:

    • Aplikacija 1 (MySQL 5.7): Pokreće se u Docker kontejneru sa MySQL 5.7
    • Aplikacija 2 (MySQL 8.0): Pokreće se u Docker kontejneru sa MySQL 8.0

    Ili kada tim radi na aplikaciji koja zavisi od specifičnih verzija Node.js-a, NPM-a ili nekih drugih biblioteka. U tom slučaju kada se koristi Docker onda tim kreira Docker sliku koja sadrži sve potrebne zavisnosti, pa se na taj način pokreće aplikacija u potpuno istom okruženju, bez brige o verzijama biblioteka.

  3. Skalabilnost aplikacije

    Docker omogućava lako skaliranje aplikacija horizontalno (dodavanje novih instanci), pa ako kompanija doživljava nagli porast saobraćaja na svojoj e-commerce platformi onda se sistem lako skalira dodavanjem dodatnih kontejnera za rukovanje većim opterećenjem, kao npr.:

    • Web serveri: 10 Docker kontejnera sa Nginx-om
    • API serveri: 15 Docker kontejnera sa aplikacijom
    • Web serveri: 15 Docker kontejnera sa MySQL-om

Osnovni Docker koncepti:

  • Docker Image (Slika): Template za stvaranje kontejnera. Definiše kako će izgledati kontejner.
  • Docker Container (Kontejner): Pokrenut primerak Docker slike.
  • Dockerfile: Datoteka s uputstvima kako kreirati Docker sliku.
  • Docker Hub: Repozitorijum za deljenje i preuzimanje Docker slika.

Instalacija Docker-a

Evo kratkog uputstva za instalaciju:

  1. Provera sistemskih zahteva:

    • Docker Desktop zahteva 64-bitni Windows 10 ili noviji sa verzijom 21H2 ili novijom, ili Windows 11.
    • Virtualizacija mora biti omogućena u BIOS-u (Hyper-V i Windows Container funkcije).
    • Instalacija zahteva najmanje 4GB RAM-a.
  2. Preuzmi Docker Desktop instalacioni program: na ovom linku ili poseti stranicu za instalaciju i klikni na dugme “Download Docker Desktop for Windows”.
  3. Pokreni instalacioni program (npr. “Docker Desktop Installer.exe”) i prati uputstva na ekranu.
  4. Restartuj računar
  5. Proveri Docker instalaciju:

    • Otvori terminal (PowerShell ili Command Prompt) i pokreni komandu:
      docker --version
    • Ako vidiš verziju Dockera, to znači da je instalacija uspela.

NAPOMENA:
Postupak instalacije se može menjati od verzije do verzije, te je najbolje pogledati aktuelno stanje na oficijalnoj stranici.

Korišćenje Docker-a

Docker može da se koristi preko preuzete aplikacije Doker Desktop ili preko terminala, evo par najčešćih komandi za terminal:

  1. Preuzimanje Docker slike sa Docker Huba

    docker pull :

    Kao npr:

    docker pull nginx:latest

    ili

    docker pull nginx:1.21.0 
  2. Kreiranje slike prema uputstvu iz Dokerfile-a

    docker build [OPTIONS] PATH

    U trenutom direktorijumu:

    docker build -t naziv_slike .

    Ako se DockerFile nalazi na nekoj drugoj lokaciji:

    docker build -f /path/to/Dockerfile -t naziv_slike .

    Gde je:

    • -t: Označava (tag) sliku imenom.
    • -f: Navodi put do Dockerfilea.
  3. Prikazivanje dostupnih Docker slika

    Naredba docker images se koristi za prikazivanje liste svih Docker slika koje su trenutno sačuvane na vašem lokalnom računaru.

    docker images

    Kada koristite samo docker images bez dodatnih opcija, Docker prikazuje samo najnovije označene slike za svaki repozitorijum. Ovo znači da, ako imate više verzija slike sa različitim oznakama (tagovima), prikazuje se samo poslednja verzija. Kada dodate opciju “-a” ili “–all”, Docker prikazuje sve slike, uključujući sve verzije iste slike kao i tzv. “dangling images” tj. slike koje nemaju oznake i često su rezultat međukoraka tokom procesa građenja slike.

    docker images -a
    Primer
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    my-app              latest              12345               1 week ago          500MB
    my-app              v1.0                67890               2 weeks ago         500MB
     none               none                abcde               3 weeks ago         500MB
    

    Ova opcija omogućava da vidimo sve slike koje su sačuvane na vašem sistemu, što vam pomaže da upravljate prostorom na disku i odlučite koje slike možete obrisati.

  4. Pokretanje kontejnera

    docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

    Kao npr.:

    docker run nginx:latest

    ili sa dodatnim opcijama:

    docker run -d -p 8080:80 --name moj-nginx nginx:latest

    Značenje opcija:

    • -d: Pokreće kontejner u pozadini (detached mode)
    • -p: Mapira portove host:container (npr. 8080:80)
    • –name: Dodjeljuje ime “moj-nginx” kontejneru
  5. Spisak pokrenutih kontejnera

    docker ps [OPTIONS]

    Npr.

    docker ps

    ili sa dodatnim opcijama:

    docker ps -a

    Opcija -a prikazuje sve kontejnere, uključujući i zaustavljene.

  6. Zaustavljanje pokrenutog kontejnera

    docker stop 

    Zaustavljanje po nazivu:

    docker stop moj-nginx

    ili prema id-u:

    docker stop df61c3a9e43b
  7. Brisanje kontejnera

    docker rm 

    Brisanje po nazivu:

    docker rm moj-nginx

    NAPOMENA:
    Naredba "docker container prune" sza uklanjanje svih zaustavljenih kontejnera sa vašeg sistema. Ova naredba pomaže u oslobađanju prostora i održavanju urednog Docker okruženja uklanjanjem kontejnera koji više nisu aktivni.

  8. Brisanje Docker slike

    docker rmi 

    Npr:

    docker rmi nginx:latest

    NAPOMENA:
    “Dangling” slike su one koje nisu povezane ni sa jednim repozitorijumom ili oznakom (tagom). Obično imaju “none” kao naziv repozitorijuma i oznake. Naredba "docker image prune" se koristi za uklanjanje neupotrebljenih (dangling) Docker slika sa vašeg lokalnog sistema.

  9. Izvršavanje naredbe unutar pokrenutog kontejnera:

    docker exec [OPTIONS]  

    Npr.:

    docker exec -it neki_kontejner ls
  10. Prikazivanje logova kontejnera:

    docker logs [OPTIONS] 

    Npr. prikazivanje svih logova

    docker logs moj-nginx

    Prikazivanje zadnjih 10 linija loga:

    docker logs -f --tail 10 moj-nginx

Docker Volume

Docker volume je mehanizam za trajno skladištenje podataka generisanih i korišćenih od strane Docker kontejnera. Volumeni omogućavaju da podaci prežive ponovna pokretanja kontejnera, a mogu se deliti između različitih kontejnera. Koriste se za upravljanje podacima na način koji je nezavistan od životnog ciklusa kontejnera.

Ključne karakteristike Docker volumena:
  • Trajnost podataka: Podaci smešteni u Docker volumene opstaju čak i kada kontejneri koji ih koriste budu obrisani.
  • Deljenje podataka: Više kontejnera može istovremeno koristiti isti volumen, što omogućava deljenje podataka između kontejnera.
  • Izolacija podataka: Docker volumeni su izolovani od sistema domaćina (host) i ostalih kontejnera, što doprinosi boljoj sigurnosti i organizaciji podataka.
  • Performanse: Docker volumeni obično nude bolje performanse u odnosu na skladištenje podataka direktno na fajl sistemu kontejnera.

Kreiranje i korišćenje Docker volumena:

Kreiranje volumena:
docker volume create my_volume
Pregled postojećih volumena:
docker volume ls
Korišćenje volumena u kontejneru:

Kada kreirate ili pokrećete kontejner, možete montirati volumen koristeći opciju -v ili --mount.

Korišćenje opcije -v:

docker run -d -v my_volume:/app/data my_image

U ovom primeru:

  • my_volume je naziv volumena koji montirate.
  • /app/data je direktorijum unutar kontejnera gde će volumen biti montiran.
  • my_image je Docker slika koju koristite za kreiranje kontejnera.

Korišćenje opcije --mount:

docker run -d --mount source=my_volume,target=/app/data my_image

Ova sintaksa je slična, ali pruža više fleksibilnosti i čitljivosti.

Upravljanje Docker volumenima:

Brisanje volumena:

docker volume rm my_volume

Automatsko brisanje volumena:

Kada želite da uklonite sve nepovezane (dangling) volumene, koristite naredbu:

docker volume prune
Primer upotrebe:

Pretpostavimo da imate aplikaciju koja skladišti podatke u direktorijumu /app/data unutar kontejnera. Želite da osigurate da ti podaci budu trajni i dostupni čak i ako ponovo pokrenete kontejner.

1. Kreirajte Docker volumen:
docker volume create app_data
2. Pokrenite kontejner i montirajte volumen:
docker run -d --name my_app_container -v app_data:/app/data my_app_image

Podaci kreirani u /app/data unutar kontejnera my_app_container biće sačuvani u volumenu app_data, koji možete koristiti sa drugim kontejnerima ili pristupiti direktno ako je potrebno.

Docker Compose

Docker Compose je alat koji olakšava upravljanje višekontejnerskim Docker aplikacijama. Koristeći jednostavni YAML fajl (docker-compose.yml), možemo da definišemo konfiguraciju svih servisa, mreža i volumena koji čine našu aplikaciju, a zatim ih pokrenete i upravljate njima pomoću jedne komande. Docker Compose je uključen u sklopu Docker Dektop instalacije.

YAML (YAML Ain’t Markup Language):

YAML je format za serializaciju podataka koji je dizajniran da bude jednostavan za čitanje i pisanje. Podaci su organizovani u parove ključeva i vrednosti. Ključ i vrednost se odvajaju dvotačkom i jednim razmakom. Struktura podataka u YAML-u definiše se pomoću uvlačenja razmacima, što omogućava jasnu hijerarhiju podataka.

ime: John Doe

Rečnici se definišu pomoću ključeva i vrednosti, sa uvlačenjem koje pokazuje koji ključevi pripadaju kojem rečniku.

osoba:
  ime: Jane Doe
  godine: 25

Liste se predstavljaju pomoću crtica sa jednim razmakom ispred svakog elementa liste.

voće:
  - Jabuka
  - Pomorandža
  - Banana

Komentari u YAML-u počinju sa # i mogu biti postavljeni bilo gde u liniji.

# Ovo je komentar
ključ: vrednost

Primer

U ovome primeru je prikazan doker-compose.yml fajl sa uputstvima za aplikaciju sa dva servisa: frontend (Vue.js aplikacija) i backend (NestJS API):

version: '3'
services:
  backend:
    build: ./backend
    ports:
      - "3000:3000"
  frontend:
    build: ./frontend
    ports:
      - "8080:8080"
    depends_on:
      - backend

Gde je backend servis (NestJS API) opisan u DockerFile:

# Dockerfile za backend

#Koristimo zvaničnu Node.js sliku verzije 18 kao osnovu za kreiranje novog kontejnera
FROM node:18

# Postavljamo radni direktorijum unutar kontejnera na /app
WORKDIR /app

# Kopiramo package.json i package-lock.json u /app direktorijum
COPY package*.json ./

# Instaliramo zavisnosti iz package.json
RUN npm install

# Kopiramo ostatak koda u /app
COPY . .

# Gradimo aplikaciju
RUN npm run build

# Pokrećemo aplikaciju koristeći npm run start:prod
CMD ["npm", "run", "start:prod"]

I frontend servis (Vue.js aplikacija) opisan u DockerFile:

# Dockerfile za frontend

#Koristimo zvaničnu Node.js sliku verzije 18 kao osnovu za kreiranje novog kontejnera
FROM node:18

# Postavljamo radni direktorijum unutar kontejnera na /app
WORKDIR /app

# Kopiramo package.json i package-lock.json u /app direktorijum
COPY package*.json ./

# Instaliramo zavisnosti iz package.json
RUN npm install

# Kopiramo ostatak koda u /app
COPY . .

# Pokrećemo aplikaciju koristeći npm run serve
CMD ["npm", "run", "serve"]
Objašnjenje koraka
  • FROM node:18:

    Koristi zvaničnu Node.js sliku verzije 18 kao osnovu za kreiranje novog kontejnera.

  • WORKDIR /app:

    Postavlja radni direktorijum na /app. Ako direktorijum postavljen sa WORKDIR ne postoji, Docker ga automatski kreira.

    • Sledeće naredbe u Dockerfile-u će se izvršavati relativno prema ovom direktorijumu.
    • Na primer, ako naredba COPY . . sledi nakon WORKDIR /app, sve datoteke će biti kopirane u /app. COPY, ADD i druge naredbe koje koriste fajl ili direktorijum kao argument oslanjaju se na relativne puteve prema trenutnom radnom direktorijumu.
  • COPY package*.json ./:

    Kopira package.json i package-lock.json iz trenutnog direktorijuma na hostu u trenutni radni direktorijum unutar kontejnera (/app).

    • ./ ukazuje na radni direktorijum (postavljen sa WORKDIR).
  • RUN npm install:

    Izvršava npm install unutar trenutnog radnog direktorijuma (/app).

    • Instalira sve Node.js zavisnosti prema package.json.
  • COPY . .:

    Kopira sav preostali kod iz trenutnog direktorijuma na hostu u trenutni radni direktorijum unutar kontejnera (/app).

  • CMD [“npm”, “start”]:

    Postavlja komandnu liniju za pokretanje aplikacije koristeći npm start.

Struktura projekta:

project
│
├── docker-compose.yml
├── backend
│   ├── Dockerfile
│   └── src
│       └── main.ts
│   └── package.json
└── frontend
    ├── Dockerfile
    └── src
        └── main.js
    └── package.json

Za pokretanje apilikacije je potrebno da se u terminalu “prebacimo” do lokacije projekta:

cd project

A zatim pokrenemo Docker Compose na sledeći način:

docker-compose up -d

Nakon čega možemo da pogledamo aplikaciju u pretraživaču:

 http://localhost:8080