- Introduzione
- Principali comandi docker
- Principali comandi Linux
- Lavorare con le immagini
- Lavorare con i container
- Docker-compose
- Deploy
- Immagini docker
- Risorse
Introduzione
- Installazione di Docker in locale
- https://docs.docker.com/get-docker
- In windows assicurarsi che nelle funzionalità si abbia attivato Hyper-V e i Container.
- Docker hub
- Container vs Virtual Machine
- Entrambi danno la possibilità di eseguire applicazioni con tutti i software necessari e le buone versioni in completo isolamento.
- La differenza principale sta nelle risorse che le VM mangiano al computer che le esegue. Una VM ha bisogno di simulare un OS e avere allocate una parte non irrisoria delle risorse fisiche.
- Ogni container condivide il KERNEL dell’OS che lo ospita (non è necessario avere licenze aggiuntive).
- In Windows 10 è possibile eseguire Windows + Linux container (Windows 10 ha built-in anche il Linux Kernel).
- E’ un processo particolare perchè ha il suo proprio file system (fornito dall’immagine docker che è eseguita nel container).
- Un container interroga il server tramite RESTful API (Architettura Client/Server.
- Docker Architecture =>
- Docker deamon
- E’ un servizio in esecuzione nel docker server.
- E’ responsabile della gestione dei container.
- Può attivarli o disattivarli
- Registra i log delle attività dei container.
- Fa il build dei container sulla base delle ‘images’ scelte.
- Espone strumenti di gestione tramite API.
- Immagini
- Sono file statici che contengono il software da eseguire.
- Sono memorizzati nel file system e aspettano di essere eseguiti.
- Sono i mattoni per creare i container.
- Registry (docker image repository)
- Sono dei repository dove è possibile trovare le immagini con cui creare i container.
- Possono essere publici (accessibili in Internet) o privati (accessibili solo dal proprio computer o all’interno di una Intranet).
- E’ possibile fare il ‘pull’ di un’immagine presente in un’registry’. Modificarla e poi usarla come base per il nostro container.
- I principali registry sono:
- DockerHub
- Amazon ECR (Elastic container registry)
- Azure ACR (Azure container registry)
- Client
- Espone una CLI per poter realizzare tutte le operazioni necessarie per creare e gestire i nostri container.
- Docker deamon
Principali comandi Docker [docker..]
-
[d=docker] -- LAVORE CON LE IMMAGINI d info d images [visualizzo le immagini presenti nel mio docker] d image ls [visualizzo e immagini presenti nel mio docker] d image prune [fa il pruning (sfoltire) delle immagini pendenti (dangling)] d image rm <img-id> [rimuove l'immagine indicata] d images -q | % { docker rmi $_ } [rimuove tutte le immagini presenti nel mio docker] d history <img-name> [mostra tutti i layers di cui è costituita l'immagine] d build -t <my-img> <app_path> [crea l'imm <my-image> dai file presenti in <app_path>] d build -t <my-img>:<img-tag> <app_path> d image tag <my-img>:<old-tag> <my-img>:<mew-tag> [modificare il tag di un'immagine] -- salvare un'immagine d image save -o <dest-path.zip|tar> <my-rep>:<tag> [salvo l'immagine in nel file zippato specificato] d image load -i <dest-path.zip|tar> [creo l'immagine dal file zippato specificato] d tag <image_old_name> <image_new_name>:tag [modificare il nome di un'immagine] -- PUBBLICARE SU DOCKERHUB creare su dockerhub un repository con lo stesso nome dell'immagine che si vuole pushare, poi => d build -t <my-rep>:<new-tag> [1 - fare un nuovo build con il nuovo tag] d image tag <my-rep>:<new-tag> <dokhub-usr>/<my-rep>:<new-tag> [2 - taggare il build al repo in remoto] d login [3 - loggarsi du dockerhub] d push <dochub-usr>/<my-rep>:<new-tag> [4 - fare il push dalla nuova build] -- policy per i nomi delle immagini che si voglio pushare sul dockerhub local_image_name = <docherhub_user>/<local_image_name> d push leperegoriot1977/<mylocalimage> LAVORARE CON I CONTAINER -- lancio un nuovo container d run hello-world [docker run = docker create + docker start] [lancia una piccola immagine di test] d run <my-img>[:<tag>] [lancia l'img, se non in locale, ne fa prima il download] d run -d <my-img>[:<tag>] [lancia l'img in (-d) detached mode cioè in background] d run -name <cont-name> <my-img>[:tag] [lancia l'img associandogli il nome <cont-name>] d run -it <my-cont> [eseguo il cont in modo iterativo, apro la shell] d run -it <my-cont> <shell> [eseguo il cont aprendo la shell al boot (<bash> o <sh>)] d run -it --rm <my-image> 3 [eseguo l'immagine <my-image>, aprendo la shell, --rm => elimina il container quando la shell è terminata] -- eseguo cont mappando porta dell'host d run -d -p 80:3000 <my-img> [eseguo e mappa la porta host 80 alla porta 3000 del cont. L'app del cont è visibile sull'host a http://localhost:80] d inspect <my-cont> [Visualizzo le info relative al container indicato] [trovo l'IP Address a cui interrogare il container] d container list -a [visualizzo tutti i container presenti nel mio docker] -- eseguo comandi in un cont running d exec -it -u <user> <my-cont> <shell> [eseguo il cont e apro la shell con l'utente indicato] d exec <cont-name> <cmd> [eseguo il comando indicato <cmd> nel cont col dato nome] -- liberare risorse d container prune [fa il pruning dei container, eliminando quelli stoppati] --visualizzo container d ps [mostra i container/processi attualmente running] d ps -a [mostra i conteiner/processi, anche quelli fermati] -- operazioni in loop d ps -a -q | % { docker rm $_ } [visualizzo tutti i processi attivi e li rimuovo in loop] -- fermo e riavvio container d stop <cont-id> [arresta il <container-id>] [ferma il container <cont-id> d start -i <cont-id> [riavvia il container <cont-id> che era fermo] -- container logs d logs [-f | -n | -t] <cont-id> [visualizzo log] -- rimuovere container d [container] rm -f <cont-id> [rimuovo cont. -f forza la rimozione di un cont running] TRASFERIRE FILE DA HOST a CONTAINER d cp <my-cont>:<file-to-copy> . [Copio nella root dell'app (.) sull' host il file specificato <file-to-copy> presente nel containter <my-cont>] d cp <file-to-copy> <my-cont>:<dest-path> [Copio in <dest-path> nel cont. <my-cont> il <file-to-copy> presente sul computer host che lancia il container stesso] BINDING HOST-CONTAINER folder (utile in DEV) d run -dp 80:3000 -v ${PWD}:<dest-path> <img-id> [Collego la root dell'app sull'host con il folder <dest-path> nel container così ogni modifica viene riflessa senza build] LAVORARE CON I VOLUME d volume create <my-vol> [creo il nuovo volume <my-vol>] [\\wsl$\docker-desktop-data\version-pack-data\community\docker\volumes\<my-vol> => path fisico nell'host Windows] d volume inspect <my-vol> [vedo il contenuto del volume <my-vol>] d volume ls [visualizzo la lista di volumi] d volume prune [rimuovo i volumi non usati] d run -d -p 80:81 -v <my-vol>:<vol-path> <my-img> [eseguo mappando <my-vol> al folder <vol-path> in <my-img>] [es: d run -d -p 5000:3000 -v app-data:/app/data react-app] PULIRE DOCKER d system prune -a d volume rm $(docker volume ls -q -f dangling=true) d system df CARTELLA DOVE SI IL DISCO VIRTUALE WSL2 wsl -l -v [visualizza lo stato delle distribuzioni WSL presenti sull'HOST] wsl --shutdown [arresta tutte le distribuzioni WSL in esecuzione sull'HOST C:\Users\<my-user>\AppData\Local\Docker\wsl\data\ext4.vhdx [path del disco virtuale che docker usa per storare tutte le immagini, container quando usa WSL2] INVIARE DATI ALL'APPLICAZIONE -- [I parametri dopo
--
sono trasmessi all'app in esecuzione nel container e non trasmessi al comando docker] CONNETTERSI A UN CONTAINER IN ESEGUIZIONE docker start <my-cont> [Avvio il container <my-cont>] docker attach --sig-proxy=false <my-cont> [Mentre un container è in esecuzione è possibile connettervici per visualizzarne i risultati] [attacco quindi la console da cui sto eseguendo i comandi all'output del processo eseguito nel container] [--sig-proxy=false
fa sì che Ctrl + C non arresti il processo ma solamente distacchi la console]- Images vs container =>
- Creando un’immagine docker si crea una sorta di template che può essere istanziato molte volte creando molti container
-
docker build -t imagemvc5 . docker run -d -p 8080:80 --name mvc5container imagemvc5
- Images vs container =>
-
- Mappatura porte =>
- Nella creazione di un container è necessario mappare esterne (dell’host) e le porte interne (del container)
- Nel caso usassimo la mappatura qui sotto allora all’indirizzo http://localhost:8080 usando nel browser della macchina host risponderebbe l’applicazione che punta alla porta 91 nel container docker
- Mappatura porte =>
Principali comandi Linux
-
pwd [print working directory] echo $0 [posizione del programma shell] hstory [lista dei comandi editati finora (E' possibile richiamarli scrivendo: !<numero_del_comando>] exit [uscire dalla session della shell] clear [pulire la shell] cd ~ [vado alla directory home (root per l'utente root] ctrl + C [stoppo processo troppo lento o in loop] -- working with packages apt [advanced package manage tool, package manager in Linux (come Nuget o Npm)] apt list [lista pacchetti presenti sulla macchina] apt update [aggiorna pacchetti presenti sulla macchina] apt install nano [installare un programma, es: nano] apt remove nano [rimuovere un programma, es: nano] -- file system / [root directory] bin [cartella con eseguibili e programmi] boot [cartella con programmi eseguiti al boot] dev [cartella con i file di tipo device, in Linux 1 device => 1 file] etc [cartella con i file di configurazione] home [è directory home dell'utente] root [è directory home dell'utente root] lib [cartella con le librerie e dipendenze] var [cartella con file aggiornati frequentemente (es: application data)] proc [cartella con i file che rappresentano i processi in esecuzione] -- visualizzazione file nano [semplice editor] cat [visualizzare piccoli file] more [scorrere una sola volta un file] less [leggere e ricercare parole in un file] head -n 5 e tail -n 5 [visualizza le prime e ultime 5 linee di un file] -- redirezione dell'output (>) [>] cat file1.txt > file2.txt [riendirizzo l'output cat file1.txt in file2.txt, quindi copio il file] [>>] echo DB_USER=nico >> .bashrc [aggiungo una linea di testo al file .bashrc] -- trovare file grep -ir Hello /etc [cerco ricorsivamente (-r) e insensitive (-i) la parola Hello in /etc] find [<path>] -type f -name "fail*" [visualizza nella corrente directory dei file con nome fail*] find [<path>] -type d [elenco delle sole cartelle presenti nell'attuale directory] -- concatenare istruzioni mkdir test ; cd test ; echo done [; => concetena operazioni e le esegue tutte anche in caso di errore] mkdir test && cd test && echo done [&& => concatena operazioni ma le esegue fino ad un errore] mkdir test || echo done [|| => esegue il primo cmd. Solo se non è riuscito, eseguire il secondo] ls /bin | less [| => concatena 2 comandi eseguendoli entrambi] mkdir test ;\ cd test ;\ echo done [\ => suddividere un comando lungo su molte linee] [In windows powershell si usa backtick (`)] -- variabili globali printenv [lista di tutte le variabili globali] echo $PATH [leggo variabile globale PATH] export DB_USER=Nico [creo la variabile locale 'Nico' per la sessione] source <path> [ricarica il file indicato senza uscire e rientrare nella sessione shell] --processi ps [visualizzo la lista dei processi] kill <PID> sleep 100 & [& => lancio il processo indicato in background] -- gestire utenti useradd -m John [aggiungo l'utente John e creo la sua cartella home] adduser [versione nuova che al suo interno chiama useradd] cat /etc/passwd [informazioni sugli utenti, anche l'ultimo che ho appena aggiunto] usermod -s /bin/bash John [modifico il programma shell per l'utente John] userdel -- gestire gruppi groupadd <nome_grup> cat /etc/group usermod -G <nome_grup> <nome_utente> [aggiungo a <nome_utente> il gruppo supplementare <nome_grup>] groups <nome_utente> [visualizzo la liste dei gruppi di un dato utente] groupmod groupdel -- permission chmod u+x <file_name> [add permesso di exe x per l'utente che è l'owner di <file_name>] chmod og+x+w-r <file_name> [add permessi di exe e scrittura, levo la lettura a <others> e <group>]
Lavorare con le immagini
- Dockerfile => Per poter lanciare un’applicazione in un container docker è sufficente aggiungere un file ‘dockerfile’ di configurazione a tale applicazione con le informazioni necessarie a Docker per impacchettare l’applicazione in un’immagine e poterla poi eseguire in un container.
- Un’immagine docker può contentere
- Versione ridotta dell’OS.
- I file dell’applicazione.
- Un’ambiente di runtime (es: node).
- Librerie di terze parti.
- Variabili globali.
- Un’immagine docker può contentere
- Immagine docker
- Kernel =>
- Normalmente un’immagine docker è una strututtura a cipolla che si base su un kernel
- Base image =>
- Sopra il kernel normalmente c’è un’immagine ridotta di un sistema operativo (Alpine o Debian)
- Writable container =>
- Solo in cima a tale struttura c’è una parte scrivibile della nostra immagine, gli strati inferiori o intermedi sono in sola lettura.
-
docker build -t <nome-immagine> <docker_file_path> - esempio: [docker build -t react-app .] - prima di lanciare il comando, verificare di aver aggiunto alla cartella dell'applicazione il dockerfile. Livelli - quando un'immagine è buildata viene eseguito il dockerfile e ad ogni nuova istruzione di esso si crea un nuovo layer (con i soli file aggiunti o modificati a seguito dell'esecuzione del comando corrispondente). Cache - Docker si accorge se qualcosa è cambiato e decide se rilanciare il comando del dockerfile oppure recuperare il layer corrispondente dalla cache. Se un livello è cambiato. Tutti i successivi saranno ricreati. Ottimizzare il file - Iniziare con le istruzioni più stabili (che non cambiano nel tempo) - Mettere nelle ultime righe le istruzione o file che posso cambiare più frequentemente
- Kernel =>
- Escludere file
- .dockerignore => per poter ignorare alcuni file presenti nella cartella delle progetto da dockerizzare è sufficiente aggiungere il file .dockerignore e indicare quali file escludere
- Creare un utente != root
- Di default la nostra immagine è eseguita dall’utente root e non vogliamo fare il deploy di una tale impostazione per motivi di sicurezza. E’ quindi utile preparare i comandi per creare un utente con meno privilegi e aggiungerlo ad un gruppo con lo stesso nome.
-
addgroup <prim_group> [creo gruppo che sarà quello primario dell'utente da creare] adduser -S -G <prim_group> <user_name> [creo utente di tipo system e lo associo al primary group. Normalmente utente e gruppo hanno lo stesso nome] oppure in un unica riga add group <prim_group> && adduser -S -G <prim_group> <user_name>
-
- Di default la nostra immagine è eseguita dall’utente root e non vogliamo fare il deploy di una tale impostazione per motivi di sicurezza. E’ quindi utile preparare i comandi per creare un utente con meno privilegi e aggiungerlo ad un gruppo con lo stesso nome.
- Dockerfile
- Docker è attivo dal 2013.
- Cosa è =>
- Un file senza estensione che ha le informazioni necessarie affinché le applicazioni che si voglino deploiare usando i container docker funzionino.
- E’ una sorta di ricetta che ci dice come fare il build di un’immagine
- Permette in altri termini di customizzare l’immagine scelta per il nostro container.
- E’ possibile dare istruzioni al docker deamon per fare molte operazioni tra cui:
- Copiare file.
- Eseguire comandi sul SO.
- Cambiare la directory di lavoro.
- Esempio1 =>
-
-- ogni comando crea un livello successivo, che ha solo i file modificati rispetto al comando precedente FROM [specifico l'immagine di base da utilizzare] COPY <source_path> <dest_path> [posso copiare file e directory dall'applicazione all'immagine docker] ADD <source_path> <dest_path> [ADD = COPY + gestione URL path + gestione ZIP file] WORKDIR </app> [specifica la cartella di default => posso usare path rel. nell'img docker] CMD <shell_form> o <exec_form> [esegue comandi al boot del container (comando <run>), più flessibile] ENTRYPOINT <shell_form> o <exec_form> [esegue comandi al boot del container (comando <run>), meno flessibile] RUN [esegue commandi durante il build dell'immagine (comando <build>)] ENV [per impostare variabili d'ambiente] EXPOSE [setto la porta su cui il container sarà in ascolto] USER [specifico l'utente con cui eseguire i comandi successivi] -- esempio 1 FROM node:alpine COPY ["my file1.txt"] ["."] [Copio sull'img docker un file specifico un uno spazio nel suo nome] CMD ["node", "app.js"] -- esempio 2 FROM node:14.16.0-alpine3.13 COPY . /app/ [copio tutti i file (.) dell'applicazione alla cartella '/app' nell'img docker] -- esempio 3 FROM node:alpine -- esempio 4 FROM node:alpine As build WORKDIR /app COPY index.ts . RUN npm install -g typescript \ && tsc index.ts FROM nginx:alpine [scelgo una version di alpine con il web server nginx installato] WORKDIR /usr/share/nginx/html [setto la working directory = /usr/share/nginx/html, così nel file system dell'immagine ogni volta che uso . faccio riferimento a tale directory] COPY index.html . [sopra questa immagine, metto la mia applicazione web, copio il file index.html (del mio file system) nella cartella /usr/share/nginx/html all'interno dell'immagine] COPY --from=build /app/index.js ---------------------------------- RUN addgroup app && adduser -S -G app app [aggiungo l'utente <app> e lo associo al nuovo gruppo <app>] USER app [setto l'utente da usare per i comandi successivi] WORKDIR /app [imposto la cartella di default => posso usare path relativi a tale cartella] COPY package*.json * [copio solo i file necessari a installazioni terze] RUN npm install COPY . . [copio il resto dei file. source(.)= tutti i file del folder progetto, dest(.)= folder root = WORKDIR] ENV API_URL=<my_api_url> [setto variabile globale] EXPOSE 3000 [l'applicazione contenuta nel container sarà in ascolto sulla porta 3000] CMD ["npm", "start"] [esegue <npm start> ad ogni <run> del container] oppure CMD npm start
-
-
- Esempio2 =>
-
-
- dockerfile =>
- Per poter deployare le 2 applicazioni (es: Inventory e Accounting) in docker è necessario creare l’opportuno ‘docker file’
- In Visual Studio aggiungere ad ognuno dei due progetti un file senza estensione:
- MVC 5 docker file =>
-
FROM microsoft/aspnet //recupera l'immagine already-made con windows OS e .NET già installati COPY .bin/Release/Publish /inetpub/wwwroot //indico di copiare i file dalla cartella di release locale (il computer host che ospita docker) //il path è relativo a dove si trova il dockerfile //a quella presente nell'immagine
-
- MVC 5 docker file =>
- dockerfile =>
-
-
-
-
-
- MVC Core docker file =>
-
//gestisco il build FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-env #imposto la cartella di lavoro rispetto alla root della cartella #contenente i file da cui partire per creare il container #se la cartella non esiste, viene creata #possiamo dire che il comando WORKDIR esegue implicitamente mkdir e cd WORKDIR /App # copio ogni cosa COPY . ./ # recupero tutte le referenze necessarie alla app RUN dotnet restore # lancio il publish e faccio il build della versione di release della mia app RUN dotnet publish -c Release -o out //gestisco l'esecuzione FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS runtime WORKDIR /App //Creo un container a partire dall'immagine e ne eseguo l'applicazione //Copia l'applicazione pubblicata nel container e ne definisce il punto d'entrata COPY --from=build-env /App/out . ENTRYPOINT ["dotnet","Dotnet.Docker.dll"]
-
- MVC Core docker file =>
-
-
-
-
-
- .dockerignore => E’ necessario aggiungere un file per indicare quali file non considerare
-
**/bin/ **/obj/
-
- Creo le immagini docker per ospitare le 2 applicazioni =>
- Creo una cartella nel computer host dal quale si lancia l’istanza docker e vi copio
- i file della cartella bin
- dockerfile
- .dockerignore file
- Creo l’immagine e il container per l’applicazione MVC5
-
//nel computer host dove è abbiamo installato docker //apro la shell e mi posiziono nella cartella dove ho copiato i file con il build della mia applicazione MVC 5 //e il dockerfile e il .dockerignore file docker build -(t)ag imageMVC5 -(f)ile dockerfile . //-t sta per tag significa dare un nome all'immagine che si sta creando //-f indica il path dove si trova il dockerfile //il punto
.
definisce il contesto di generazione dell'immagine //creo il container //-d sta per detached mode (il container è in background mode) docker run -(d)etach -p 8080:91 --name mvc5container imageMVC5
-
- Creo una cartella nel computer host dal quale si lancia l’istanza docker e vi copio
- .dockerignore => E’ necessario aggiungere un file per indicare quali file non considerare
-
Lavorare con i container
-
[d=docker] --avviare e fermare container d start -i <container-id> [Avvia i container arrestati. docker start != docker run] d stop <container-id> [Arresta il container indicato] --visualizzare log d logs [-f|-n |-t] <container-id> [-f=--follow, -n=--tail] --pubblicare le porte d run -d -p 80:30 <my-img> [esegue il cont mappando la sua porta 30 alla porta 80 in host] --eseguire i comandi in un container in eseguzione d exec <container-name> <cmd> --rimuovere container d [container] rm -f <container-id> [-f=--force, la parola chiave <container> può essere omessa] d container prune [fa il pruning dei container non più in esecuzione -- creare d volume create <my-vol> d run -d -p 80:81 -v <my-vol>:<vol-path> <my-img> [es: docker run -d -p 80:81 -v app-data:/app/data react-app] -- trasferire file tra host e container d cp <my-container>:<file-to-copy> . [. => copio i file nella root dell'app sull'host] d cp <file-to-copy> <my-container>:<dest-path> -- condividere il codice sorgente dell'app -- con il container che lo ospita d run -d -p 80:81 -v ${PWD}:<dest-path> <img-id> [linka la root dell'app sull'host al folder indicato sul cont Il path sull'host deve essere assoluto]
Docker-compose
- Container multi-applicazione
- E’ possibile lavorare su più applicazioni (o sottoapplicazioni) insieme.
- Per esempio buildare immagini , avviare e arrestare i relativi container per un’applazione costituira dal frontend (react) , dal backend (node.js) e dal db (mongo).
- Bisognare creare un file di configurazione con l’esplicitazione dei 3 servizi (docker-compose.yml) e usare il comando <docker-compose>.
- Installlare docker compose (https://docs.docker.com/compose/install)
-
docker-compose --version [Verifico se docker compose è già installato]
-
- Ripulire il workspace
- Tramite l’applicazione Docker Desktop
- Aprire l’applicazione Docker Desktop => Cliccare sull’icona ‘Troubleshoot’ => Cliccare ‘Clean and purge data’
- Tramite linee di comando
-
-- visualizzo la liste degli ID di tutti i container e le immagini presenti nel nostro workspace docker container ls -q [lista degli ID dei container presenti nel nostro workspace] docker image ls -q [lista degli ID delle immagini presenti nel nostro workspace] -- rimuovo prima tutti i container docker container rm -f $(docker container ls -qa) [rimuovo i container passando la liste degli ID al cmd <rm> -f => forzo la rimozione anche dei container in esecuzione -qa => visualizzo gli ID anche dei container arrestati] -- rimuovo in seguito tutte le immagini docker image rm $(docker image ls -q) [rimuovo tutte le immagini passando la liste degli ID al cmd <rm>] -- alla fine non ci devono più essere nè immagini nè processi (attivi o non) docker images docker ps -a
-
- Tramite l’applicazione Docker Desktop
- Configurare docker-compose [docker-compose.yml]
-
--docker-compose.yml version: "3.8" services: frontend: depends_on: - backend build: ./frontend [path dove trovo il Dockfile di configurazione per il front-end] ports: - 3000:3000 [setto la porta 3000 dell'host in ascolto sulla porta 3000 del cont.] volumes: - ./frontend:/app frontend-test: [posso creare un container in + per testare l'app] image: vidly_frontend volumes: - ./frontend:/app command: npm test backend: depends_on: - db build: ./backend [path dove trovo il Dockfile di configurazione per il back-end] ports: - 3001:3001 [scelgo una porta differente rispetto al front-end] environment: DB_URL: mongodb://db/vidly command: ./docker-entrypoint.sh [posso sovrascrivere i CMD definiti nel dockfile relativo all'app] volumes: - ./backend:/app [mappo la cartella root nell'app backend con la cartella /app presente nel cont relativo così che ogni cambio nel codice sorgente possa essere visibile nel cont senza dover fare il rebuild Il path può essere un path relativo] db: image: mongo:4.0-xenial [non faccio il build, ma importo l'immagine di mongo dal cloud] ports: - 27017:27017 [setto porta di defualt per il server mongo] volumes: - vidly:/data/db [attacco il volume <vidly> alla cartella del container </data/db>] volumes: vidly: [comando per la creazione del volume <vidly> per persistere i dati del DB]
-
- Network
-
- Quando si fa il build di una multi-app tramite docker-compose, quest’ultimo crea automaticamente una struttura (network) per far dialogare i vari servizi (applicazioni) di cui è composta la nostra multi-app.
- Ad ogni container viene assegnato un IP da un DNS-SERVER presente nativamente in docker . Nel container il componente DNS-Resolver permette di recuperare tali IP dal nome del container (servizio) così come configurato nel file docker-compose.yml
- Ogni container può vedere gli altri registrati sotto lo stesso network.
-
- Migrazione DB
- Se tra le app che abbiamo composto per creare la nostra multi-app abbiamo per empio un DB e vogliamo che gli altri container attendato affinche il servizio DB sia attivo prima di lanciare degli script di migrazione ad esempio, dobbiamo utilizzare dei tool utilizzati in docker per permettere l’attesa (ad: wait-for)
- Cercare in Internet “docker wait for container”
- Principali comandi docker-compose [docker-compose..]
-
[d-c = docker-compose] -- fare il build di una multi-app d-c build [--no-cache] [--no-cache non usa la cache durante il building. Verrà creata una immagine per ogni servizio definito in docker-compose.yml. Tutte le immagini prendo come prefisso la cartella del progetto] -- avviare multi-app d-c up -d [--build] [con il file docker-compose.yml questo comando aggiorna le dipendenze di cui la nostra multi-app ha bisogno. --build => permette di fare il build prima di eseguire -d => lancia l'applicazione in modo detached] -- arrestare multi-app d-c down [stoppa i container legati alla multi-app. Le immagini restano] -- visualizzo i relativi container in esecuzione d-c ps [mostra i processi (container) in uso per la mia multi-app Mentre <docker ps> mostra ogni container configurato nell'host] -- visualizzo i network docker network ls [visualizzo i network presenti sull'host] -- visualizzo log docker-compose logs -f [visualizzo i log di tutti i container della mia multi-app] docker logs <cont-id> -f [posso sempre visualizzare i log di un solo container alla volta]
-
- Docker compose postgreSQL + pgAdmin
-
//docker-compose.xml (postgreSQL + pgAdmin) version: '3.8' services: db: container_name: pg_container image: postgres restart: always environment: POSTGRES_USER: root POSTGRES_PASSWORD: root POSTGRES_DB: test_db ports: - "5432:5432" pgadmin: container_name: pgadmin4_container image: dpage/pgadmin4 restart: always environment: PGADMIN_DEFAULT_EMAIL: admin@admin.com PGADMIN_DEFAULT_PASSWORD: root ports: - "5050:80" //Nella cartella dove é memorizzato il file docker-compose.xml lanciare docker compose up //Dal browser del computer host navigare alla console di amministrazione di pgAdmin http://localhost:5050/. Per sapere quale IP dare al server postgreSQL lanciare docker ps docker inspect <container-id> //cercare Networks/pgadmin_default/IPAddress
-
Deploy
- Virtualization vs Containerization =>
- Nell’esempio sotto un progetto è diviso in due app separate (Inventory e Accounting)
-
- Virtualization (VMWare / Hypervisor / VirtualBox) =>
- Complica il deploy.
- Duplica OS
- Non è interessante il fatto di avere multipli OS (si vorrebbe piuttosto multiple istanze delle mie applicazioni).
- Container =>
- Invece di creare nuove VM con ognuna un suo sistema operativo si creano dei container usano una container technology come docker.
- Kernel namespace
- Le tecnologie basate sui container (come docker) non replicano interamente un sistema operativo.
- Piuttosto cercano di condividere il kernel del sistema operativo host per creare degli spazi isolati.
- Per tale ragione il meccanismo della containerizzazione è molto più efficiente del meccanismo della virtualizzazione.
- Per usare docker è necessario avere attivata la virtualizzazione BIOS nel sistema operativo host.
- Un container è un package contenente:
- il software,
- le sue dipendenze
- i file di configurazione.
- Un container è un’istanza di un’immagine
- Vantaggi
- Prevedibilità
- Un container può facilmente essere copiato dai computer di sviluppo o test al server di produzione.
- Permettendo così di evitare il classico problema legato al deploy di applicazioni funzionanti in ambiente di sviluppo e test ma una volta deployate in produzione non funzionano.
- E’ il principale vantaggio.
- Compatibile con i principali provider cloud.
- Performance
- Un container si inizializza molto più velocemente che una VM.
- Densità
- Un server può gestire migliaia di container contro solo qualche dozzina di VM.
- Prevedibilità
- Svantaggi
- Isolamento => Visto che i container condividono lo stesso SO del computer HOST, l’isolamento è minore che nel caso di VM.
- Virtualization (VMWare / Hypervisor / VirtualBox) =>
- Deploy verso un cluster
- Kubernetes
- Docker Swarm
- Deploy verso un single-host
- VPS
- Digital Ocean
- Google Cloud Platform (GCP)
- Microsoft Azure
- Amazon Web Service (AWS)
- Installare docker-machine (https://github.com/docker/machine/releases)
-
-- tramite uno dei servizi di VPS possibili installiamo la nostra applicazione docker sul server docker-machine create ` --driver <my-drive> ` --digitalocean-access-token <my-token> <app-server-name> -- connettersi all'host remoto sul server del servizio scelto docker-machine shh <app-server-name> -- creo un file docker-compose.prod.yml specifico per l'ambiente di produzione version: "3.8" services: frontend: build: context: ./frontend dockerfile: Dockerfile.prod ports: - 80:80 restart: unless-stopped [per ogni servizio, indico cosa fare in caso il server cada] backend: build: ./backend ports: - 3001:3001 environment: DB_URL: mongodb://db/vidly restart: unless-stopped db: image: mongo:4.0-xenial ports: - 27017:27017 volumes: - vidly:/data/db restart: unless-stopped volumes: vidly: -- Per ottimizzare la dimensione delle immagini è possibile creare -- dei file dockerfile.prod specifici per l'ambiente di produzione # Step 1: build stage FROM node:14.16.0-alpine3.13 AS build-stage WORKDIR /app COPY package*.json ./ RUN npm install COPY . . RUN npm run build # Step 2: production FROM nginx:1.12-alpine AS production-stage RUN addgroup app && adduser -S -G app app USER app COPY --from=build-stage /app/build /urs/share/nginx/html [copio i file dalla cartella dell'app /app/build alla cartella specificata sul server] EXPOSE 80 ENTRYPOINT [ "nginx", "-g", "deamon off;" ] -- Faccio il build della nuova immagine con il nuovo dockerfile docker build -t <new-image-name> -f dockerfile.prod . -- faccio il build delle nuove immagini tutte insieme docker-compose -f docker-compose.prod.yml build
- VPS
Immagini docker
-
1 -- SQL SERVER --eseguire l'immagine sql server, impostandone la passwrdo e la porta docker run --name SqlServer -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=<my-passowrd>" -p 1433:1433 -d mcr.microsoft.com/mssql/server:2019-latest -- copiare la cartella dei log del container in locale -- (es: C:\Users\richlab\Docker\Log) docker cp <container_id>:/var/opt/mssql/log/errorlog <local_log_path> 2 -- MONGODB docker run -d -p 27017-27019:27017-27019 --name mongodb mongo:4.0.4 3 -- PostgreSQL docker run --name my-postgres -p 5432:5432 -e POSTGRES_PASSWORD=mypassword -d postgres nella shell psql -d postgres -U postgres poi CREATE DATABASE myDB; CREATE USER myUser WITH PASSWORD ‘myPassword’; GRANT ALL PRIVILEGES ON myDB TO myUser;
Risorse
- E’ possibile trovare una lista delle più importanti immagini di base (docker engine).
- Docker-compose postgresql + pgAdmin