Înapoi la catalog
Season 29 18 Episoade 1h 9m 2026

Docker Masterclass

Ediția 2026. Un curs audio complet despre Docker, care acoperă bazele containerelor, imagini, Dockerfile, networking, Compose, CI/CD și cele mai noi funcționalități AI precum MCP Toolkit, Docker Sandboxes și Docker Agent.

Containerizare DevOps
Docker Masterclass
Se redă acum
Click play to start
0:00
0:00
1
Promisiunea Dev Egal Prod
Descoperă de ce Docker a schimbat fundamental dezvoltarea de software. Acest episod acoperă propunerea de valoare principală a separării aplicațiilor de infrastructură și obținerea parității perfecte între mediile de development și producție.
3m 29s
2
Containere vs Mașini Virtuale
Înțelege diferențele arhitecturale dintre containere și mașini virtuale (VMs). Află cum containerele obțin izolarea prin partajarea kernel-ului gazdă, devenind incredibil de ușoare în comparație cu hypervisor-ele tradiționale.
3m 42s
3
Anatomia unei imagini Docker
Explorează ce este de fapt o imagine Docker. Acest episod explică principiile imutabilității imaginilor și compoziția layerelor, arătând cum modificările sistemului de fișiere sunt suprapuse pentru a crea un șablon de container.
3m 57s
4
Schița Dockerfile
Învață cum să scrii un Dockerfile pentru a construi imagini personalizate. Acoperim instrucțiuni esențiale precum FROM, RUN și CMD și explicăm diferența crucială dintre formele shell și exec.
3m 58s
5
Stăpânirea Build Cache-ului
Optimizează construirea imaginilor folosind build cache-ul din Docker. Află de ce ordinea instrucțiunilor din Dockerfile este critică pentru a preveni instalarea inutilă a dependențelor.
4m 09s
6
Build-uri Multi-Stage
Păstrează-ți imaginile de producție curate și sigure. Acest episod introduce multi-stage builds, demonstrând cum să separi mediul greoi de compilare de mediul minimal de runtime.
4m 04s
7
Rularea și Interacțiunea
Învață mecanica practică a rulării containerelor. Acoperim modurile detached versus interactive, publicarea de bază a porturilor și cum să execuți comenzi shell în interiorul unui container care rulează.
4m 12s
8
Bazele Persistenței Datelor
Previno pierderea catastrofală a datelor atunci când containerele sunt șterse. Acest episod compară Bind Mounts pentru hot-reloading în dezvoltarea locală cu Docker Volumes pentru persistența sigură a bazelor de date.
3m 41s
9
Networking pentru Containere
Înțelege cum gestionează Docker traficul de rețea. Află bazele publicării porturilor către host și cum comunică containerele în siguranță între ele prin rețele bridge izolate.
4m 07s
10
Introducere în Docker Compose
Treci dincolo de comenzile pentru un singur container. Află cum Docker Compose folosește un fișier YAML declarativ pentru a defini, interconecta și orchestra mai multe servicii simultan.
4m 21s
11
Docker în Pipeline-ul CI/CD
Elimină testele instabile cu medii de build containerizate. Acest episod acoperă modul de utilizare a Docker în pipeline-urile de Continuous Integration pentru a garanta teste automate perfect reproductibile.
3m 45s
12
Imagini Multi-Platformă
Rezolvă nepotrivirea dintre Apple Silicon și Cloud Server. Află cum Docker Buildx îți permite să cross-compilezi și să împachetezi aplicații pentru arhitecturile ARM și AMD64 simultan.
4m 03s
13
Docker MCP Toolkit
Conectează-ți în siguranță agenții AI la instrumentele locale. Acest episod introduce Docker Model Context Protocol (MCP) Toolkit, explicând cum să gestionezi serverele MCP containerizate folosind cataloage și profiluri.
3m 30s
14
Auto-Discovery cu Dynamic MCP
Explorează Dynamic MCP, o funcționalitate experimentală care permite clienților AI să caute în Docker MCP Catalog și să instaleze dinamic noi servere de instrumente în timpul unei conversații, fără configurare manuală.
3m 59s
15
Docker Sandboxes pentru AI
Înțelege arhitectura Docker Sandboxes. Află de ce agenții AI autonomi de programare necesită microVM-uri izolate cu daemoni Docker dedicați, în loc de namespace-uri standard de containere.
3m 58s
16
Construirea Echipelor de Agenți AI
Nu te mai baza pe un singur model AI pentru sarcini complexe. Acest episod introduce framework-ul Docker Agent, arătând cum să compui echipe specializate de agenți definite în YAML.
4m 01s
17
Toolset-uri și Workflow-uri pentru Agenți
Fă-ți agenții AI cu adevărat utili oferindu-le constrângerile potrivite. Află cum să configurezi toolset-uri pentru sistemul de fișiere și să impui workflow-uri structurate de dezvoltare în Docker Agent.
3m 37s
18
Modele AI în Compose
Tratează-ți LLM-urile locale exact ca pe orice altă dependență a aplicației. Află cum să declari, să configurezi și să asociezi modele AI direct în fișierul tău YAML Docker Compose.
3m 25s

Episoade

1

Promisiunea Dev Egal Prod

3m 29s

Descoperă de ce Docker a schimbat fundamental dezvoltarea de software. Acest episod acoperă propunerea de valoare principală a separării aplicațiilor de infrastructură și obținerea parității perfecte între mediile de development și producție.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Docker Masterclass, episodul 1 din 18. Tocmai ai petrecut trei zile căutând o eroare care apare doar pe serverul de staging. Codul rulează impecabil pe laptopul tău, dar în momentul în care ajunge în deployment pipeline, crapă. Vinovatul este aproape întotdeauna un system library nepotrivit, o versiune diferită de runtime sau un environment variable lipsă. Aceasta este exact fricțiunea pe care Docker a fost creat să o elimine, livrând promisiunea dev equals prod. Docker este o platformă deschisă pentru dezvoltarea, livrarea și rularea aplicațiilor. Scopul său principal este să îți separe aplicațiile de infrastructură. Istoric vorbind, developerii scriau cod, iar echipele de operations făceau provisioning la servere. Developerii predau aplicația, iar echipa de operations petrecea ore sau zile configurând host-ul pentru a îndeplini cerințele software. Această aliniere manuală a environment-urilor este fragilă și lentă. Docker rezolvă acest lucru împachetând aplicația împreună cu dependențele, tool-urile de sistem, library-urile și runtime-ul ei într-o unitate standardizată numită container. Ai putea asocia acest concept cu mașinile virtuale tradiționale. Deși au în comun obiectivul de a izola aplicațiile, containerele sunt mult mai lightweight, deoarece nu necesită un sistem de operare guest complet. Vom discuta despre această diferență arhitecturală în episodul următor. Acum ne concentrăm pe ceea ce realizează această împachetare. Iată ideea cheie. Pentru că un container conține atât codul, cât și environment-ul exact necesar pentru a-l executa, mașina host de bază devine în mare parte irelevantă. Docker se asigură că, dacă un container rulează pe laptopul tău local de development, va rula exact la fel pe un server de QA și exact la fel într-un data center de production. Elimini fraza it works on my machine, deoarece mașina ta și mașina de production oferă acum exact același environment de execuție. Workflow-ul arată în felul următor. Un developer scrie cod local și definește environment-ul necesar într-un fișier de configurare plain text. Docker citește acel fișier și construiește un artefact static numit image. Acel image unic și imuabil este cel care este testat. Când testele trec, exact același image primește deploy în production. Nu copiezi cod pe un server și nu rulezi un setup script. Muți întregul environment de lucru ca o singură unitate sigilată. Această portabilitate schimbă modul în care sistemele scalează. Pentru că aceste containere sunt standardizate și lightweight, pornirea de noi instanțe ale unei aplicații ca răspuns la un traffic spike se întâmplă în câteva secunde. Poți transfera cu ușurință workloads între diferite environment-uri, mutând o aplicație de pe un server local de testare la un cloud provider, fără să schimbi o singură linie de cod sau să reconfigurezi host-ul. Concluzia finală este că Docker transformă infrastructura într-o resursă previzibilă, creând o graniță rigidă în care developerii dețin întregul environment din interiorul containerului, iar echipa de operations oferă pur și simplu compute power-ul necesar pentru a-l rula. Dacă vrei să ajuți la susținerea emisiunii, caută DevStoriesEU pe Patreon. Asta e tot pentru acest episod. Îți mulțumesc că ai ascultat și continuă să construiești!
2

Containere vs Mașini Virtuale

3m 42s

Înțelege diferențele arhitecturale dintre containere și mașini virtuale (VMs). Află cum containerele obțin izolarea prin partajarea kernel-ului gazdă, devenind incredibil de ușoare în comparație cu hypervisor-ele tradiționale.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Docker Masterclass, episodul 2 din 18. Nu trebuie să bootezi un sistem de operare întreg doar pentru a rula un singur script Python. Totuși, ani de zile, developerii au acceptat un overhead mare și boot times lenți pentru a-și ține aplicațiile izolate unele de altele. Astăzi, rezolvăm asta analizând Containers vs Virtual Machines. Gândește-te că rulezi un stack complex local. Ai nevoie de un frontend React, un API Python și o bază de date PostgreSQL, toate rulând simultan. Dacă le instalezi direct pe mașina host, riști conflicte de dependențe. API-ul ar putea cere o versiune specifică a unui system library care intră în conflict cu ce are nevoie baza ta de date. Un container rezolvă asta acționând ca un proces sandboxed. Iată ideea de bază. Un container nu este un computer în miniatură. Este strict un proces care rulează nativ pe mașina ta host. Magia constă în izolare. Prin funcționalități integrate în sistemul de operare, acest proces primește propriul său filesystem privat, propriul networking stack și o perspectivă izolată asupra sistemului. Pentru API-ul Python care rulează înăuntru, pare să fie singurul software de pe mașină. Pentru sistemul tău de operare host, este doar un alt proces standard, la fel ca web browser-ul sau text editor-ul tău. Pentru că un container este doar un proces, el împarte kernel-ul sistemului de operare host. Când baza de date PostgreSQL din interiorul unui container trebuie să aloce memorie sau să scrie o înregistrare pe disk, comunică direct cu kernel-ul host. Nu există niciun intermediar și niciun sistem de operare secundar care să booteze în background. De aceea pornirea unui container este aproape instantanee. Durează exact la fel de mult ca pornirea aplicației în sine. Acum, compară asta direct cu o Virtual Machine. O Virtual Machine abordează izolarea prin simularea hardware-ului. Se bazează pe un hypervisor, care este un software ce decupează un virtual CPU, virtual memory și un virtual disk drive. Peste acest hardware fals, trebuie să instalezi un sistem de operare guest complet. Dacă vrei să rulezi același API Python într-un VM izolat, trebuie să bootezi o întreagă distribuție Linux. VM-ul își încarcă propriul kernel separat, inițializează device drivers și pornește servicii de sistem în background înainte măcar să se gândească să execute codul tău Python. De fiecare dată când aplicația trebuie să citească un fișier, request-ul trece prin sistemul de operare guest, coboară la hypervisor și, în final, ajunge la hardware-ul host. Asta oferă o izolare de securitate incredibil de puternică, dar vine cu un cost uriaș în CPU cycles, memory usage și boot time. Din cauza acestor diferențe, o concepție greșită comună este că trebuie să alegi una sau alta. În realitate, containerele și Virtual Machines nu se exclud reciproc. În mediile cloud moderne, sunt aproape mereu folosite împreună. Când faci provision la o cloud instance, închiriezi o Virtual Machine. Acea Virtual Machine oferă o graniță puternică la nivel de hardware, separându-ți workload-ul de alți clienți de pe același server fizic. Apoi instalezi un container runtime în interiorul acelei Virtual Machine pentru a-ți rula frontend-ul React, API-ul și baza de date. Virtual Machine-ul izolează infrastructura, în timp ce containerele izolează aplicațiile individuale. Distincția se reduce în cele din urmă la granițe. Virtual Machines virtualizează hardware-ul pentru a rula mai multe sisteme de operare, în timp ce containerele virtualizează sistemul de operare pentru a rula mai multe procese izolate. Mulțumesc că ai petrecut câteva minute cu mine. Până data viitoare, numai bine.
3

Anatomia unei imagini Docker

3m 57s

Explorează ce este de fapt o imagine Docker. Acest episod explică principiile imutabilității imaginilor și compoziția layerelor, arătând cum modificările sistemului de fișiere sunt suprapuse pentru a crea un șablon de container.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Docker Masterclass, episodul 3 din 18. Faci deploy la o aplicație și funcționează perfect. Două săptămâni mai târziu, repornești exact aceeași aplicație pe aceeași mașină și dă crash pentru că o librărie de sistem s-a actualizat singură în background. Acest environmental drift silențios este exact ceea ce eliminăm înțelegând anatomia unei imagini Docker. Mai întâi, hai să clarificăm cel mai frecvent punct de confuzie. O imagine nu este un container. O imagine este un template static. Conține codul aplicației tale, librăriile, tool-urile de sistem și runtime-ul. Un container este pur și simplu o instanță în execuție a acelei imagini. Poți porni o mie de containere dintr-o singură imagine, dar imaginea în sine stă pur și simplu pe disc, așteptând să fie citită. Caracteristica definitorie a unei imagini Docker este imutabilitatea. Odată ce o imagine este creată, aceasta nu este niciodată modificată. Nu poți schimba un fișier de configurare dintr-o imagine existentă. Dacă vrei să schimbi o imagine, trebuie să faci build la una complet nouă. Această imutabilitate garantează că o imagine testată pe laptopul tău se comportă identic în producție. Template-ul nu poate suferi un drift în timp. Dacă nu poți modifica o imagine, trebuie să faci build la altele noi. O imagine Docker nu este un singur fișier masiv. Este o compoziție de mai multe layere independente, suprapuse unul peste altul. Fiecare layer reprezintă un set specific de modificări ale filesystem-ului, ceea ce înseamnă adăugarea, modificarea sau ștergerea de fișiere. Gândește-te la o aplicație Node dot js. Rareori faci build la sistemul de operare tu însuți. În schimb, începi cu o imagine de bază. Această imagine de bază conține o distribuție Linux minimală și runtime-ul Node. Acea bază este de fapt alcătuită din propriile ei layere, dar pentru tine, acționează ca o fundație. Când îți adaugi aplicația la această fundație, Docker îți înregistrează modificările ca noi layere suprapuse. Mai întâi, aduci fișierul de configurare a dependențelor. Asta creează un nou layer. Apoi, instruiești sistemul să descarce și să îți instaleze dependențele. Toate acele librării descărcate sunt împachetate în următorul layer. În cele din urmă, copiezi codul sursă al aplicației. Asta formează layer-ul superior. Când pornești un container, Docker stivuiește aceste layere folosind un union filesystem. Asta face ca toate layerele independente să arate ca o structură standard de directoare. Dacă exact același file path există în două layere, versiunea din layer-ul superior o ascunde pe cea din layer-ul inferior. Iată ideea cheie. Pentru că layerele sunt imutabile, ele sunt puternic ținute în cache și share-uite. Dacă îți actualizezi codul sursă al aplicației și faci build la o imagine nouă, Docker calculează ce s-a modificat. Vede că imaginea de bază Linux, runtime-ul Node și layer-ul de dependențe sunt identice cu build-ul anterior. Reutilizează instantaneu acele layere existente și creează doar un layer nou pentru codul tău actualizat. Asta transformă un deployment care ar putea dura minute într-o operațiune de câteva milisecunde. Această arhitectură economisește, de asemenea, spațiu pe disc și bandwidth de rețea. Când dai push la noua imagine pe un server, transmiți doar acel singur layer care conține noul cod sursă. Serverul are deja layerele de bază. Prin impunerea de layere imutabile, Docker garantează că mediul aplicației tale nu se poate modifica în tăcere, asigurându-se în același timp că transmiți sau stochezi doar exact octeții pe care i-ai modificat. Asta e tot pentru acest episod. Ne auzim data viitoare!
4

Schița Dockerfile

3m 58s

Învață cum să scrii un Dockerfile pentru a construi imagini personalizate. Acoperim instrucțiuni esențiale precum FROM, RUN și CMD și explicăm diferența crucială dintre formele shell și exec.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Docker Masterclass, episodul 4 din 18. Întregul mediu de operare pentru aplicația ta complexă poate fi exprimat în doar zece linii de plain text. Dai un singur fișier unui build system și obții un sistem perfect configurat, gata să ruleze oriunde. Acesta este Dockerfile Blueprint. Un Dockerfile este un document text care conține toate comenzile pe care un utilizator le-ar putea apela în command line pentru a da build unei imagini. Formatul este simplu. Fiecare linie începe cu o instrucțiune, scrisă cu majuscule prin convenție, urmată de argumentele pentru acea instrucțiune. Docker citește acest fișier linie cu linie, de sus în jos. Fiecare Dockerfile valid trebuie să înceapă cu o bază. O definești folosind instrucțiunea FROM. Dacă scrii FROM ubuntu, Docker face pull imaginii oficiale Ubuntu și o folosește ca punct de plecare. Fiecare linie ulterioară din fișierul tău va modifica acest mediu de bază. Odată ce baza ta este setată, de obicei trebuie să instalezi dependențe. Faci acest lucru folosind instrucțiunea RUN. Instrucțiunea RUN execută orice comandă în interiorul imaginii curente și face commit rezultatului. Dacă scrii RUN apt-get update urmat de comenzile de instalare a pachetelor, Docker pornește mediul, rulează package manager-ul, instalează software-ul și salvează noua stare. Apoi, ai nevoie de aplicația propriu-zisă. Un sistem de operare cu dependențe instalate este inutil fără codul tău. Instrucțiunea COPY se ocupă de acest lucru. Oferi o cale sursă din workspace-ul tău local și o cale destinație în interiorul imaginii. Docker îți preia fișierele și le copiază direct în filesystem-ul containerului. Procesul de build al imaginii este doar prima fază. De asemenea, trebuie să-i spui lui Docker ce aplicație să lanseze atunci când pornește un container. Definești acest comportament default folosind fie instrucțiunea CMD, fie ENTRYPOINT. Iată ideea cheie. Există două moduri distincte de a formata aceste instrucțiuni de execuție, iar amestecarea lor provoacă bug-uri subtile. Prima abordare este forma shell. Scrii instrucțiunea urmată de comandă exact așa cum ai tasta-o într-un terminal. Când Docker vede asta, îți încapsulează comanda într-un shell, executând-o prin bin slash sh. Asta este convenabil deoarece variabilele de mediu se extind automat. Cu toate acestea, procesul shell stă între Docker și aplicația ta. Dacă Docker trimite un semnal pentru a opri gracefully containerul, shell-ul îl prinde și aplicația ta nu îl primește niciodată, ceea ce duce la terminări forțate. A doua abordare este forma exec. Aceasta este scrisă ca un array JSON. O formatezi cu paranteze pătrate, oferind executabilul ca primul string și argumentele sale ca string-uri ulterioare. Când folosești forma exec, Docker ocolește complet shell-ul. Îți rulează executabilul direct. Aplicația ta devine process ID unu în interiorul containerului. Asta garantează că semnalele sistemului trec direct către aplicația ta, asigurând shutdown-uri line și previzibile. Dacă vrei un container de producție stabil, folosește întotdeauna forma exec pentru comenzile finale, astfel încât aplicația ta să își controleze propriul lifecycle. Asta e tot pentru acest episod. Mulțumesc pentru audiție și continuă să construiești!
5

Stăpânirea Build Cache-ului

4m 09s

Optimizează construirea imaginilor folosind build cache-ul din Docker. Află de ce ordinea instrucțiunilor din Dockerfile este critică pentru a preveni instalarea inutilă a dependențelor.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Docker Masterclass, episodul 5 din 18. Dacă build-ul tău Docker durează zece minute de fiecare dată când modifici o singură linie de cod sursă, faci ceva greșit. Soluția constă în întregime în modul în care îți structurezi fișierul, iar asta înseamnă să stăpânești build cache-ul. Când declanșezi un build Docker, builder-ul procesează Dockerfile-ul secvențial, de sus în jos. Fiecare instrucțiune, fie că este vorba de copierea unui director sau de rularea unui script, generează un layer separat în imaginea rezultată. Pentru că executarea acestor pași necesită timp de procesare și lățime de bandă, Docker salvează automat output-ul fiecărui pas într-un build cache local. La build-urile ulterioare, engine-ul încearcă să refolosească aceste layere salvate pentru a sări peste munca redundantă. Pentru a determina dacă este posibil un cache hit, Docker evaluează fiecare instrucțiune în raport cu istoricul de cache existent. Pentru instrucțiunile care rulează comenzi, verifică dacă string-ul comenzii în sine este identic cu cel folosit în build-ul anterior. Pentru instrucțiunile care copiază fișiere de pe host în imagine, Docker merge cu un pas mai departe. Calculează un checksum pentru conținutul și metadatele fiecărui fișier copiat. Apoi compară acest nou checksum cu checksum-ul fișierelor din layer-ul salvat anterior în cache. Dacă checksum-urile se potrivesc perfect, Docker refolosește layer-ul din cache și trece la linia următoare. Dacă diferă chiar și un singur byte, cache-ul este invalidat. Fii atent la partea asta. Invalidarea cache-ului este o reacție în lanț strictă. În secunda în care Docker detectează o modificare și invalidează un layer, nu se mai uită la cache pentru restul build-ului. Fiecare instrucțiune care vine după layer-ul invalidat este forțată să se execute de la zero. Acest lucru se întâmplă pentru că fiecare layer se bazează pe starea exactă a layer-ului de dinaintea lui. Această reacție în lanț dictează modul în care trebuie să îți organizezi Dockerfile-ul. Gândește-te la o aplicație Node în care gestionezi dependențe externe. O greșeală frecventă este să folosești o singură instrucțiune pentru a copia întregul folder al proiectului în imagine, urmată de o instrucțiune care rulează comanda de instalare a pachetelor. Dacă modifici o singură linie într-un fișier text undeva în codul sursă, checksum-ul pentru instrucțiunea de copiere se modifică. Cache-ul se rupe la acel pas. Prin urmare, următoarea instrucțiune este forțată să ruleze. Aștepți să se descarce din nou sute de megabytes de dependențe, chiar dacă lista ta reală de dependențe a rămas complet neatinsă. Abordarea optimă izolează dependențele de codul aplicației. Mai întâi, adaugi o instrucțiune pentru a copia doar fișierul de configurare a dependențelor, mai exact package manifest-ul, în imagine. În al doilea rând, rulezi comanda pentru a descărca dependențele. În al treilea rând, adaugi o instrucțiune separată pentru a copia restul codului sursă general. Acum, când modifici același fișier text și dai rebuild, Docker evaluează prima instrucțiune. Manifest-ul dependențelor nu s-a modificat, așa că este folosit cache-ul. Trece la pasul de instalare. Din moment ce layer-ul precedent a fost un cache hit, iar string-ul comenzii este identic, cache-ul este folosit din nou aici, sărind peste descărcarea masivă. Cache-ul se rupe doar la instrucțiunea finală, unde builder-ul copiază fișierele sursă actualizate. O așteptare de zece minute devine o actualizare de două secunde. Cel mai eficient mod de a-ți accelera pipeline-ul este să îți ordonezi instrucțiunile strict de la cele care se schimbă cel mai rar la cele care se schimbă cel mai des. Asta e tot pentru acest episod. Îți mulțumesc că ai ascultat și continuă să construiești!
6

Build-uri Multi-Stage

4m 04s

Păstrează-ți imaginile de producție curate și sigure. Acest episod introduce multi-stage builds, demonstrând cum să separi mediul greoi de compilare de mediul minimal de runtime.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Masterclass Docker, episodul 6 din 18. Să faci deploy la compilatorul tău în producție reprezintă un risc masiv de securitate și mărește dimensiunea containerului cu gigabytes. Tu scrii clean code, dar artifactul tău final este tras în jos de toate tool-urile grele necesare doar pentru a-i face build. Soluția la această problemă sunt multi-stage builds. Când faci build la aplicații în limbaje compilate precum Java, Go sau C++, procesul de compilare necesită build tools, software development kits și cod sursă brut. Istoric vorbind, developerii foloseau o abordare standard în care instalau toate aceste dependențe în container, compilau codul și apoi rulau aplicația. Problema este că toate acele build tools rămân în imaginea finală de producție. Ajungi să faci deploy la compilatorul tău, la package manager-ul tău și la fișierele intermediare alături de aplicația ta propriu-zisă. Acest lucru îți face containerul enorm. Durează mai mult să faci pull prin rețea la containerele mari, iar acestea consumă mai mult spațiu de stocare. Și mai rău, creează o suprafață de atac masivă. Dacă un atacator îți sparge containerul, are brusc la dispoziție un development environment complet echipat. O concepție greșită des întâlnită este că rezolvarea acestei probleme necesită menținerea a două fișiere separate - un fișier pentru a face build la software și un script pentru a extrage rezultatul și a-l transmite unui al doilea fișier pentru deploy. Nu este cazul. Multi-stage builds gestionează toată această separation of concerns într-un singur fișier. Iată ideea cheie. Un multi-stage build îți permite să definești secvențial mai multe medii distincte, sau stages. Fiecare stage începe prin definirea propriului base image. Începi primul stage cu un base image greu care conține toate development tools-urile tale. Îi atribui acestui stage un nume, cum ar fi builder. În interiorul acestui builder stage, îți copiezi codul sursă de pe mașina locală și execuți comenzile de compilare. Builder stage-ul face greul, generând fișierul executabil final. Apoi, mai jos în exact același fișier, definești un al doilea base image. Asta inițiază un stage complet nou. Pentru acest stage, alegi un runtime image minimal. Acest mediu conține doar dependențele exacte necesare pentru a rula aplicația, cu zero build tools. În loc să copiezi din nou fișierele de pe mașina locală, folosești o instrucțiune copy specializată. Această instrucțiune îi spune build engine-ului să se întoarcă în builder stage, să ia doar artifactul finalizat și compilat, și să-l pună în noul tău stage minimal. Când build engine-ul termină, produce un container bazat exclusiv pe stage-ul final. Totul din primul stage - compilatorul, pachetele descărcate, codul sursă - este complet eliminat. Nu ajunge niciodată în imaginea ta de producție. Ia în considerare un scenariu concret care implică o aplicație Java Spring Boot. În fișierul tău, primul stage folosește un image Maven voluminos. În interiorul acestui stage, execuți comanda Maven pentru a face package la aplicația ta. Maven descarcă toate dependențele necesare ale proiectului, compilează codul Java și îi face package într-un fișier JAR finalizat. Apoi, începi al doilea stage folosind un base image lightweight de Java Runtime Environment. Nu instalezi Maven în acest mediu. Nu copiezi fișierele sursă Java aici. În schimb, instruiești engine-ul să copieze doar fișierul JAR compilat direct din stage-ul Maven în acest runtime environment minimal. În cele din urmă, setezi comanda implicită pentru a executa acel fișier JAR. Prin separarea strictă a build environment-ului de runtime environment, garantezi că acel container de producție este complet izolat de build tools-urile tale. Imaginea finală vede doar artifactul compilat și runtime-ul minim necesar, menținând deploy-ul tău rapid, suplu și extrem de sigur. Asta e tot pentru episodul ăsta. Ne auzim data viitoare!
7

Rularea și Interacțiunea

4m 12s

Învață mecanica practică a rulării containerelor. Acoperim modurile detached versus interactive, publicarea de bază a porturilor și cum să execuți comenzi shell în interiorul unui container care rulează.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Docker Masterclass, episodul 7 din 18. Pornirea unui proces în background este exact ce îți dorești pentru un server web de producție. Dar când acel server refuză să îți încarce pagina, ai nevoie de o metodă să spargi sticla, să intri în environment și să vezi ce e stricat de fapt. Acest episod acoperă rularea și interacțiunea cu containerele. Comanda principală pentru a porni orice container este docker run. By default, dacă rulezi un container, acesta își atașează output-ul direct pe ecranul terminalului tău. Îți preia prompt-ul și, dacă apeși control C, containerul se oprește. Pentru un serviciu long-running, cum ar fi un server web Nginx, acest lucru este complet nepractic. Vrei ca serverul să ruleze în background. Obții asta folosind flag-ul de detached mode, pe care îl tastezi ca dash d. Când pasezi dash d, Docker pornește containerul, îți printează un container ID lung și unic pe ecran și îți dă imediat înapoi prompt-ul terminalului. Containerul continuă să ruleze liniștit în background. Totuși, acel container care rulează este izolat. Chiar dacă Nginx servește activ trafic pe portul 80 în interiorul containerului, mașina ta host nu îl poate vedea. Trebuie să faci explicit o gaură prin acea izolare de rețea. Faci asta cu flag-ul publish, tastat ca dash p. Asta îți permite să mapezi un port specific de pe laptopul tău host la un port specific din interiorul containerului. Dacă specifici dash p 8080 colon 80, Docker interceptează orice trafic web care ajunge pe laptopul tău pe portul 8080 și îl rutează direct către portul 80 din interiorul containerului. Acum ai un server web detached pe care îl poți accesa cu succes din browserul tău local. Dar ce se întâmplă când încarci pagina și vezi o eroare de configurare? Serverul tău Nginx rulează în background, dar trebuie să citești fișierele de configurare de pe filesystem-ul său. Iată ideea cheie. Nu trebuie să oprești un container ca să te uiți în el. În schimb, folosești comanda docker exec. În timp ce docker run creează un container complet nou, docker exec rulează o comandă complet nouă în interiorul unui container deja existent, care rulează. Ca să obții un terminal util și funcțional, trebuie să combini două flag-uri specifice în dash i t. I-ul vine de la interactive. Asta ține canalul de standard input deschis, permițându-ți să tastezi efectiv comenzi în container. T-ul alocă un pseudo-TTY. Asta păcălește containerul să creadă că este conectat la un terminal fizic, ceea ce este necesar pentru ca prompt-urile de comandă și formatarea textului să se afișeze corect. Dacă rulezi docker exec dash i t, urmat de numele containerului și comanda slash bin slash bash, ajungi instantaneu într-un command prompt în interiorul containerului Nginx care rulează. Acum ești în interiorul cutiei. Poți să citești fișiere de configurare, să verifici error logs și să inspectezi filesystem-ul exact așa cum ai face-o pe un server Linux standard. Când ai terminat, dacă tastezi exit îți închizi sesiunea temporară de shell. Containerul Nginx în sine rămâne complet neafectat, rulând în continuare în background. În cele din urmă, va trebui să faci curățenie. Rularea comenzii docker stop cu numele containerului trimite un semnal de terminare, oferind aplicației timp să se închidă gracefully. Totuși, oprirea unui container nu îl șterge din sistemul tău. Containerul oprit rămâne pe hard drive, păstrându-și log-urile și orice modificări interne ale filesystem-ului. Ca să-l ștergi definitiv și să eliberezi acel spațiu pe disc, rulezi comanda docker rm. Cea mai critică distincție de memorat este diferența dintre run și exec. Docker run bootează un sistem izolat complet nou, în timp ce docker exec îți permite să intri într-un sistem care deja respiră. Mulțumesc pentru audiție. Aveți grijă de voi, tuturor.
8

Bazele Persistenței Datelor

3m 41s

Previno pierderea catastrofală a datelor atunci când containerele sunt șterse. Acest episod compară Bind Mounts pentru hot-reloading în dezvoltarea locală cu Docker Volumes pentru persistența sigură a bazelor de date.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Docker Masterclass, episodul 8 din 18. Faci deploy la o bază de date într-un container, scrii mii de rânduri și totul rulează perfect. Apoi ștergi containerul pentru a face update la imagine, iar întreaga bază de date dispare pentru totdeauna. By default, storage-ul containerului este strict temporar. Pentru a preveni pierderea datelor, avem nevoie de Data Persistence Basics. Când un container pornește, acesta creează un writable layer deasupra imaginii sale de bază. Orice fișiere pe care containerul le creează sau le modifică sunt stocate în acest layer specific. Dacă containerul este distrus, acel layer este distrus odată cu el. Datele sunt complet efemere. Nu există în afara lifecycle-ului propriu al containerului. Pentru a păstra datele în siguranță, trebuie să le direcționezi în afara containerului și pe mașina host. Docker oferă două mecanisme principale pentru asta: bind mounts și managed volumes. Un bind mount mapează un path specific, explicit, de pe mașina host direct către un path din interiorul containerului. Îi spui lui Docker exact ce folder de pe laptop ar trebui să apară în environment-ul containerului. Acest lucru depinde în mare măsură de sistemul de operare de pe host și de structura fișierelor locale. Mașina host păstrează controlul deplin asupra fișierelor. Această abordare este perfectă pentru local development. Faci bind mount la directorul local cu source code în path-ul aplicației web a containerului. Când editezi și salvezi un script pe laptop, containerul citește imediat acel fișier updatat. Ai instant hot-reloading, fără să dai rebuild la imaginea containerului de fiecare dată când modifici o linie de cod. Al doilea mecanism este un managed volume. În loc să indici un path specific pe care îl controlezi pe hard disk, îi ceri lui Docker să creeze o entitate de storage. Docker face provision la spațiul de pe mașina host și îl gestionează complet. Nu trebuie să știi unde plasează fizic Docker fișierele pe sistemul host. Trebuie doar să dai volumului un nume și să îi spui containerului unde să îi facă mount intern. Volumele sunt soluția standard pentru database persistence. Când rulezi PostgreSQL, creezi un volum rulând o comandă simplă și dându-i un identificator, cum ar fi db-data. Apoi, când pornești containerul, pasezi un configuration flag care leagă acel volum db-data de path-ul intern unde Postgres își scrie table records. Dacă oprești și ștergi containerul bazei de date, Docker lasă volumul complet neatins. Când faci spin up la un container nou ulterior, pur și simplu atașezi acel volum existent, iar toate înregistrările tale sunt intacte. Iată ideea cheie. Alegerea dintre aceste două metode se reduce la cine trebuie să acceseze fișierele. Folosește bind mounts atunci când mașina host trebuie să interacționeze activ cu datele, cum ar fi un developer care editează source code. Folosește managed volumes atunci când containerul deține datele, cum ar fi un database engine care scrie înregistrări, și vrei doar ca Docker să păstreze aceste fișiere în siguranță la restarturile containerului. Containerele efemere sunt o alegere de design, nu un defect, deoarece te obligă să decuplezi datele de runtime compute. Presupune întotdeauna că acel container va fi distrus imediat și mapează explicit persistent state-ul în afara acestuia. Dacă găsești aceste episoade utile, poți susține emisiunea căutând DevStoriesEU pe Patreon. Asta e tot pentru acest episod. Mulțumesc pentru audiție și continuă să construiești!
9

Networking pentru Containere

4m 07s

Înțelege cum gestionează Docker traficul de rețea. Află bazele publicării porturilor către host și cum comunică containerele în siguranță între ele prin rețele bridge izolate.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Docker Masterclass, episodul 9 din 18. Implicit, un container care rulează este complet izolat de lumea exterioară. Se află într-o bulă privată și, dacă vrei ca internetul să ajungă la el, trebuie să faci intenționat găuri în acea izolare. Gestionarea acestor găuri și a conexiunilor dintre containere este treaba Container Networking. Când un container pornește, Docker îi atribuie o adresă IP internă. De obicei, containerul poate accesa internetul pentru a descărca update-uri sau a face network calls, dar nimic din afara mașinii host nu poate ajunge înăuntru. Pentru a accepta incoming traffic, folosești port publishing. Acest publishing ia un port de pe mașina ta fizică host și îi face bind direct la un port din interiorul containerului. Dacă ai un container cu un web server care face listen intern pe portul optzeci, îi poți da publish pe portul optzeci-optzeci de pe host-ul tău. Când un user trimite un request către mașina ta host pe portul optzeci-optzeci, Docker îl interceptează și îi face forward direct prin firewall către container, pe portul optzeci. Configurezi acest mapping la startup folosind flag-ul publish. Fără acel flag, containerul rămâne inaccesibil pentru rețeaua externă. Asta acoperă traficul extern. Acum, a doua parte din asta este comunicarea internă. Aplicațiile rulează rareori ca un singur proces izolat. De obicei, ai mai multe containere care trebuie să facă share la date. Implicit, Docker atașează fiecare container nou la o rețea built-in numită default bridge. Un bridge este un network switch software care rulează pe mașina ta host. Conectează containerele ca să poată schimba pachete, izolându-le în același timp de rețelele externe. Aici e ideea cheie. Acest default bridge permite containerelor să comunice folosind adresele lor IP interne, dar adresele IP ale containerelor se schimbă de fiecare dată când un container își dă restart sau update. Să faci hardcoding la o adresă IP în configurația aplicației tale îți va strica sistemul aproape imediat. Ca să rezolvi asta, creezi o rețea user-defined bridge. Când atașezi mai multe containere la un user-defined bridge custom, Docker oferă DNS resolution intern automat. Asta înseamnă că aceste containere se pot găsi între ele folosind exact numele lor de container. Gândește-te la un scenariu în care ai un container cu o aplicație backend și un container de database. Creezi o singură rețea custom bridge și atașezi ambele containere la ea. În codul aplicației tale backend, nu scrii un connection string pentru database folosind o adresă IP fragilă. Pur și simplu folosești numele containerului de database ca adresă de host. Docker interceptează acel DNS query, găsește containerul de database pe acel bridge specific și face route la trafic către adresa IP internă corectă, în mod dinamic. Acest design îți oferă control total asupra securității aplicației. Backend-ul și database-ul pot vorbi liber între ele prin acel custom bridge, dar niciun trafic extern nu poate ajunge la database. Ca să-ți rulezi aplicația în siguranță, lași database-ul ascuns pe bridge-ul intern privat, fără published ports. Apoi, dai publish doar la portul containerului de backend către mașina ta host. Userii externi accesează portul public de backend, iar backend-ul face query în siguranță către database prin bridge-ul privat. Arhitectura aplicației tale îți dictează acel network topology: folosește published ports ca să inviți userii externi înăuntru, și rețele custom user-defined bridge ca să lași containerele interne să vorbească între ele în siguranță, folosind numele. Asta e tot pentru acest episod. Mulțumesc că m-ai ascultat și continuă să construiești!
10

Introducere în Docker Compose

4m 21s

Treci dincolo de comenzile pentru un singur container. Află cum Docker Compose folosește un fișier YAML declarativ pentru a defini, interconecta și orchestra mai multe servicii simultan.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Docker Masterclass, episodul 10 din 18. Nu ar trebui să ai nevoie de un document text plin de comenzi complexe de terminal doar pentru a-ți porni mediul local de development. Să te bazezi pe shell history pentru a ține minte exact flag-urile, porturile și numele de rețea pentru mai multe containere este un mod fragil de a lucra. Introducerea în Docker Compose rezolvă asta transformând întregul tău application stack într-un singur fișier declarativ. Când rulezi o aplicație, aceasta există rareori în izolare. De obicei, ai un web server, o bază de date și poate un caching layer. Să le pornești manual necesită rularea mai multor comenzi separate. Trebuie să creezi o rețea custom, să atașezi fiecare container la ea, să expui porturile corecte și să montezi storage drives. Dacă faci un typo în oricare dintre acești pași, containerele nu pot comunica și aplicația dă fail. Docker Compose înlocuiește acest proces imperativ cu un fișier YAML declarativ, numit în mod normal compose dot yaml. În loc să-i spui lui Docker exact ce să facă pas cu pas, declari starea finală dorită a întregului tău sistem. Docker Compose își dă seama de pașii necesari pentru a atinge acea stare. Fișierul YAML este împărțit în trei secțiuni structurale principale. Prima și cea mai importantă secțiune se numește services. Un service este pur și simplu o definiție pentru un container specific din aplicația ta. Ia un scenariu în care rulezi o aplicație Node alături de o bază de date MySQL. Sub secțiunea services, definești două intrări. O numești pe prima web, specificând imaginea de Node și porturile locale pe care vrei să le expui. O numești pe a doua database, specificând imaginea de MySQL și environment variables necesare, cum ar fi parola de root. Aici e partea cheie. Nu trebuie să conectezi manual aceste containere. By default, Docker Compose creează automat o singură rețea internă pentru aplicația ta. Atașează toate service-urile definite la această rețea și atribuie fiecărui container un hostname care corespunde numelui de service. Codul aplicației tale Node se poate conecta la baza de date pur și simplu targetând hostname-ul "database", iar DNS-ul intern îl rezolvă la IP-ul corect al containerului. Poți defini manual rețele custom în secțiunea networks a fișierului YAML, dar pentru majoritatea setup-urilor standard de development, comportamentul default face exact ce ai nevoie. Ultima piesă structurală este secțiunea volumes. Bazele de date necesită storage persistent. Dacă containerul de MySQL se închide, nu vrei ca datele tale să fie șterse. În partea de jos a fișierului tău YAML, declari un named volume. Apoi, în cadrul definiției de service a bazei de date, mapezi un path specific din interiorul containerului către acel named volume. Docker Compose gestionează crearea și lifecycle-ul acestui storage pentru tine. Odată ce fișierul tău este scris, gestionezi întregul stack cu două comenzi. Tastezi docker compose up. Compose citește fișierul YAML, creează rețeaua internă, setează acele volumes și pornește containerele de MySQL și Node. Dacă vrei să continui să lucrezi în terminalul tău, adaugi detach flag pentru a rula totul în background. Când ai terminat de lucrat, nu oprești și nu ștergi fiecare container individual. Tastezi docker compose down. Compose oprește gracefully aplicația Node, oprește baza de date și șterge containerele și rețeaua default, păstrându-ți sistemul complet curat. Îți lasă acele named volumes intacte, ceea ce înseamnă că înregistrările din baza de date te așteaptă data viitoare când ridici stack-ul. Docker Compose îți schimbă mindset-ul de la gestionarea de containere individuale izolate la gestionarea de application environments complete. Setup-ul infrastructurii tale devine o singură bucată de cod căreia îi poți da commit în version control și pe care o poți da share instant cu echipa ta. Asta e tot pentru acest episod. Mulțumesc că m-ai ascultat și continuă să construiești!
11

Docker în Pipeline-ul CI/CD

3m 45s

Elimină testele instabile cu medii de build containerizate. Acest episod acoperă modul de utilizare a Docker în pipeline-urile de Continuous Integration pentru a garanta teste automate perfect reproductibile.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Docker Masterclass, episodul 11 din 18. Faci push la cod, pipeline-ul rulează, iar testele pică. Le rulezi local și trec perfect. Serverul tău de CI are o versiune de dependency puțin mai veche decât laptopul tău. Acest drift este principala cauză a testelor flaky, dar containerizarea mediului de build face ca fiecare rulare să fie perfect predictibilă. Astăzi, vorbim despre Docker în pipeline-ul CI/CD. Istoric vorbind, Continuous Integration însemna menținerea unor servere de build statice. În timp, inginerii se conectează la aceste mașini virtuale pentru a instala pachete, a face update la runtime-uri și a ajusta configurațiile sistemului. Aceste servere se transformă în pet VMs. Acumulează state ascuns și fișiere de cache rămase în urmă. Când un pipeline pică, pierzi timpul încercând să-ți dai seama dacă e stricat codul sau dacă serverul are nevoie doar de un software update. Folosirea Docker ca mediu de build evită complet această problemă. În loc să execuți scripturile de test direct pe sistemul de operare host al unui CI worker, worker-ul ridică un container. CI runner-ul face pull la o imagine Docker specifică, pornește containerul, face mount la codul sursă și execută pașii de build în interiorul acelei limite izolate. Iată ideea cheie. Când job-ul se termină, containerul este distrus. Următoarea rulare a pipeline-ului primește un mediu complet fresh, identic. Nu există procese de background conflictuale din rulările anterioare. Mediul este stateless și definit în întregime de imagine. Gândește-te la procesul de upgrade al unui runtime de programare. Să presupunem că trebuie să-ți muți proiectul de la Node 18 la Node 20. Într-un setup tradițional, cineva trebuie să se logheze pe serverul de build, să facă update la software system-wide și să spere că nu strică alte proiecte care împart același worker. Cu Docker ca mediu de build, întregul proces este doar o modificare de string. Faci update la tag-ul imaginii de bază din configurația ta, de la Node 18 la Node 20. CI runner-ul face pull la noua imagine. Build-ul tău rulează instant în mediul updatat. Dacă un test pică, dai revert la tag și încerci din nou mai târziu. Gestionezi infrastructura direct alături de codul tău. Mai e un aspect aici. Dacă folosești Docker pentru a-ți face build la aplicație, pipeline-ul tău de CI are nevoie de capacitatea de a face build și push la imagini. Dacă job-ul tău de CI rulează deja într-un container, cum execuți comenzi de Docker build? Asta necesită un pattern numit Docker-in-Docker. Docker-in-Docker înseamnă rularea unui Docker daemon izolat în interiorul containerului tău de CI. Containerul exterior oferă mediul controlat pentru pașii din pipeline-ul tău, în timp ce daemon-ul intern procesează build-urile aplicației. Asta permite job-ului de CI să facă pull la imagini de bază, să construiască containerul aplicației și să facă push la artifact-ul final într-un registry, totul fără a polua mașina host care rulează CI worker-ul. Mutarea mediului de CI într-un container transferă controlul sistemului de build către developer. Exact aceeași imagine care face build la codul tău pe un server remote poate fi rulată pe mașina ta locală, garantând că, dacă un test pică în CI, poți reproduce exact acea eroare local. Asta e tot pentru acest episod. Mersi că m-ai ascultat și keep building!
12

Imagini Multi-Platformă

4m 03s

Rezolvă nepotrivirea dintre Apple Silicon și Cloud Server. Află cum Docker Buildx îți permite să cross-compilezi și să împachetezi aplicații pentru arhitecturile ARM și AMD64 simultan.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Docker Masterclass, episodul 12 din 18. „Funcționează la mine pe mașină” capătă un cu totul alt sens atunci când mașina ta locală folosește un procesor ARM, dar cloud-ul de producție rulează pe Intel. Testezi container-ul local, îi dai push într-un registry, îi dai pull pe server și dă crash instant cu o eroare de execution format. Problema este o nepotrivire de arhitectură hardware. Ca să repari asta, folosești Multi-Platform Images. O imagine de container este, la bază, un pachet de binare și file system-uri. Dacă dai build la o imagine pe un Mac cu Apple Silicon, binarele rezultate sunt compilate pentru arhitectura ARM64. Când dai deploy la acea imagine pe un server de cloud Linux standard care rulează un procesor AMD64, CPU-ul host-ului pur și simplu nu înțelege instrucțiunile din interiorul container-ului. În trecut, trebuia să menții build pipeline-uri separate pentru diferite target-uri hardware. Docker Buildx elimină această cerință. Docker Buildx este un plugin de command line care extinde sistemul standard de build din Docker. Folosește un engine de backend numit BuildKit pentru a executa build-uri concurent și pentru a gestiona task-uri complexe, cum ar fi targetarea mai multor platforme dintr-o singură trecere. Când dai build la o imagine multi-platformă folosind Buildx, nu înghesui două file system-uri separate într-un singur container gigantic. În schimb, Buildx creează un image manifest list. Gândește-te la acest manifest ca la un routing table. Acesta conține o listă de pointeri către diferite imagini specifice fiecărei arhitecturi, stocate în registry-ul tău. Când o mașină dă pull la imaginea ta, daemon-ul său Docker citește acest manifest, își identifică propria arhitectură de CPU a host-ului și descarcă automat doar acele image layers care se potrivesc cu hardware-ul său. Pentru a face cross-compile și a împacheta simultan un backend API pentru ambele arhitecturi, folosești comanda docker buildx build. Incluzi un flag de platform, pasându-i o listă separată prin virgulă cu target-urile tale. De exemplu, tastezi flag-ul, urmat de linux slash amd64 comma linux slash arm64. Adaugi tag-ul standard al imaginii, iar apoi adaugi un flag de push. Iată ideea de bază. Când dai build pentru mai multe platforme în același timp, nu poți pur și simplu să încarci imaginea finală multi-platformă înapoi în cache-ul engine-ului tău Docker local. Daemon-ul local nu este conceput să țină un manifest list care pointează către mai multe arhitecturi. Trebuie să instruiești Buildx să dea push la rezultate direct în container registry-ul tău. Registry-ul acționează ca un storage system care organizează corect acel manifest list și imaginile individuale pentru fiecare arhitectură. Pentru a executa fizic build-ul pentru un procesor pe care nu îl ai, Buildx se bazează pe un emulator numit QEMU. Docker Desktop configurează asta automat. Când mașina ta ARM ajunge la un pas care necesită o instrucțiune AMD64, emulatorul o traduce on the fly. Asta necesită zero modificări în Dockerfile-ul tău. Dacă ai nevoie de build times mai rapizi, poți folosi și tool-uri de cross-compilation direct în interiorul unui multi-stage build, ceea ce sare peste emulare, dar necesită setarea unor compiler flags specifice în codul tău. Adevărata putere a unui multi-platform manifest este că izolează complet consumatorul de detaliile hardware de la bază. Un developer pe un Mac și un cluster de producție care rulează Intel dau pull la exact același image tag, iar registry-ul servește automat binarul corect fiecăruia, fără nicio configurare extra. Mersi că ai petrecut câteva minute cu mine. Până data viitoare, numai bine.
13

Docker MCP Toolkit

3m 30s

Conectează-ți în siguranță agenții AI la instrumentele locale. Acest episod introduce Docker Model Context Protocol (MCP) Toolkit, explicând cum să gestionezi serverele MCP containerizate folosind cataloage și profiluri.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Docker Masterclass, episodul 13 din 18. Să oferi unui agent AI acces direct la baza ta de date sau la sistemul local de fișiere este incredibil de puternic. Dar să instalezi scripturi de integrare untrusted direct pe mașina ta host pentru a face asta este un dezastru de securitate care abia așteaptă să se întâmple. Docker MCP Toolkit rezolvă asta mutând acele integrări în containere izolate. Model Context Protocol, sau MCP, este un standard open care permite clienților de AI, cum ar fi aplicația de desktop Claude sau editorul Cursor, să se conecteze la surse de date și tool-uri externe. Pentru a-i oferi AI-ului tău o nouă capabilitate, rulezi o mică aplicație numită server MCP. În mod istoric, asta însemna să descarci scripturi third-party de Python sau Node și să le rulezi direct pe sistemul tău de operare. Asta introduce o fricțiune operațională masivă, cu conflicte de dependențe, și mai important, oferă unui cod untrusted acces nerestricționat la mașina ta. Docker MCP Toolkit rezolvă asta prin încapsularea acestor servere în containere Docker standard. Prima piesă a acestui sistem este Catalogul. Un Catalog este un registry de servere MCP verificate și containerizate. În loc să dai pull la repository-uri random de pe internet, dai pull la imagini Docker standardizate. Aceste imagini sunt pre-împachetate pentru a rula tool-urile necesare fără să aibă nevoie de runtime-uri locale pentru diverse limbaje pe mașina ta host. Odată ce ai acces la aceste servere, ai nevoie de o modalitate să le organizezi. Asta se face folosind Profile. Un Profil este o grupare de configurare care definește exact ce tool-uri sunt necesare pentru un anumit proiect. De exemplu, ai putea crea un profil numit web-dev. În interiorul acestei configurări, specifici că acest profil necesită serverul GitHub pentru citirea de repository-uri de cod și serverul Playwright pentru browser automation. Îți setezi API key-urile și variabilele de mediu pentru ambele tool-uri o singură dată, în interiorul configurării profilului. Acum, ai tool-uri izolate și un profil definit. Cum se conectează AI-ul la ele? Aici devine interesant. Conexiunea este gestionată de MCP Gateway. Gateway-ul acționează ca un router central care rulează pe host-ul tău. Nu îți configurezi clientul de AI să lanseze containere individuale. În schimb, direcționezi Claude sau Cursor către MCP Gateway și ceri profilul web-dev. Când clientul se conectează, Gateway-ul citește profilul, pornește automat containerele GitHub și Playwright solicitate în background, și stabilește conexiunea. Gateway-ul intermediază comunicarea dintre clientul de AI și containere folosind protocolul standard. Clientul de AI crede că vorbește cu tool-uri locale, dar toată execuția are loc în siguranță în interiorul Docker. Configurezi tool-urile o singură dată în profil și poți da share la acel setup exact către oricâte aplicații de AI diferite. Dacă unul dintre aceste tool-uri nu funcționează corect sau este compromis, rămâne blocat într-un container, complet orb față de restul sistemului tău. Adevărata valoare a MCP Toolkit este că separă configurarea tool-urilor tale de AI de clienții care le folosesc, oferind garanții solide de izolare fără să sacrifice inteligența workflow-urilor tale. Mulțumesc pentru audiție. Aveți grijă de voi, tuturor.
14

Auto-Discovery cu Dynamic MCP

3m 59s

Explorează Dynamic MCP, o funcționalitate experimentală care permite clienților AI să caute în Docker MCP Catalog și să instaleze dinamic noi servere de instrumente în timpul unei conversații, fără configurare manuală.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Docker Masterclass, episodul 14 din 18. Ești în mijlocul unei conversații cu un AI coding agent și îi ceri să facă un query pe o bază de date. În mod normal, dacă ai uitat să configurezi tool-ul pentru baza de date în prealabil, agentul dă fail și îți cere să intervii. Problema e că această configurare manuală a tool-urilor îți întrerupe workflow-ul. Dar cum ar fi dacă agentul și-ar da seama că îi lipsește o capabilitate, ar căuta într-un catalog și ar instala serverul necesar complet on the fly? Exact asta realizează Dynamic MCP Auto-Discovery. De obicei, să oferi tool-uri unui Large Language Model înseamnă să le definești static într-un config file înainte să începi sesiunea. Dacă agentul tău ar putea avea nevoie să citească un repository de GitHub, să posteze un mesaj pe Slack și să facă un query pe o bază de date, trebuie să încarci toate acele servere Model Context Protocol up front. Această abordare aglomerează context window-ul cu tool-uri care s-ar putea să nu fie folosite niciodată și te obligă să prezici perfect nevoile agentului. Dynamic MCP schimbă această paradigmă. Îi permite agentului să descopere și să atașeze tool-uri exact atunci când task-ul o cere, fără nicio intervenție umană. Când activezi acest feature dinamic, Docker MCP Gateway expune un set de tool-uri de management direct către agentul AI. Gateway-ul îi oferă, în esență, agentului abilitatea de a-și gestiona propriul toolchain. Cele două tool-uri critice oferite de gateway pentru acest proces sunt mcp-find și mcp-add. Agentul interacționează cu ele exact așa cum interacționează cu orice function call standard. Putem analiza cum funcționează această logică folosind un scenariu concret. Să presupunem că îi ceri agentului tău să analizeze metricile utilizatorilor stocate într-o bază de date SQL. Agentul evaluează request-ul, își verifică toolkit-ul curent și își dă seama că nu are încărcate tool-uri de query pentru baza de date. În loc să arunce o eroare, agentul invocă tool-ul mcp-find, pasând un search string relevant, cum ar fi postgres. Gateway-ul interceptează acest call și face un query în catalogul Docker MCP configurat pentru a găsi serverele disponibile care fac match cu acel string. Apoi returnează metadatele și descrierile serverelor care au făcut match înapoi către agent. Agentul citește descrierea, confirmă că serverul Postgres va rezolva problema și trece la pasul următor. Agentul invocă apoi tool-ul mcp-add, pasând identificatorul serverului Postgres pe care tocmai l-a găsit. Aici devine interesant. Gateway-ul prinde request-ul mcp-add, face pull la imaginea necesară, ridică serverul MCP într-un container Docker și face bind dinamic la noile tool-uri pe conexiunea activă. Agentul are brusc acces la tool-urile pentru baza de date, se conectează la baza ta de date, rulează query-ul pe care l-ai cerut inițial și returnează rezultatul. Întregul proces se desfășoară în background, menținând conversația complet neîntreruptă. Există un al treilea tool oferit în această suită de management pentru execuție experimentală de cod, dar acesta gestionează un set de probleme complet diferit, așa că astăzi ne concentrăm strict pe discovery. Iată aspectul cheie despre acest proces. Când agentul folosește mcp-add pentru a încărca un server nou, acea adăugare este strict scoped la sesiunea curentă. Gateway-ul nu rescrie fișierele tale globale de configurare, iar tool-urile nou adăugate nu persistă la restarturi. Când închizi sesiunea, acel tool binding temporar este distrus. Acest lucru asigură că environment-ul tău de bază rămâne curat și sigur, oferind în același timp agentului flexibilitate maximă pentru a rezolva dinamic probleme complexe, multi-step. Prin expunerea căutării în catalog și a instalării ca function calls standard, Dynamic MCP elimină povara configurării up front și îi permite agentului să își construiască propriul environment on demand. Asta e tot pentru acest episod. Mersi că m-ai ascultat și spor la construit!
15

Docker Sandboxes pentru AI

3m 58s

Înțelege arhitectura Docker Sandboxes. Află de ce agenții AI autonomi de programare necesită microVM-uri izolate cu daemoni Docker dedicați, în loc de namespace-uri standard de containere.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Docker Masterclass, episodul 15 din 18. Un agent autonom de codare AI este exact genul de proces pe care nu vrei să-l lași să ruleze cu acces root pe laptopul tău. Îi ceri să repare un bug și, dintr-o dată, descarcă pachete arbitrare, modifică fișiere de sistem sau încearcă să-ți reconstruiască infrastructura locală. Ai nevoie de un loc în care agentul să poată acționa ca un administrator fără să fie de fapt unul. Asta este exact problema pe care Docker Sandboxes for AI sunt concepute să o rezolve. În mod tradițional, Docker izolează procesele folosind namespaces și control groups din Linux. Aceste containere folosesc la comun kernelul sistemului de operare host. Pentru un serviciu web previzibil, acest model funcționează perfect. Dar un agent AI este în mod inerent imprevizibil. Generează cod neverificat, îl execută și adesea are nevoie să instaleze pachete de sistem noi on the fly pentru a-și testa propriile soluții. Să împarți kernelul de pe host cu un agent imprevizibil este un risc de securitate prea mare. Pentru a rezolva asta, Docker Sandboxes abandonează namespaces-urile standard de containere în favoarea unor microVM-uri izolate. Când pornești un sandbox pentru un agent, acesta bootează o mașină virtuală dedicată, lightweight. Agentul primește propriul kernel distinct. Nu îți poate vedea procesele de pe host. Nu poate accesa network stack-ul de pe host by default. Cel mai important, elimină complet riscul vulnerabilităților tradiționale de tip container escape. Agentul este strict izolat într-un mediu cu hardware virtualization. Asta contează enorm când te gândești la ce fac de fapt agenții AI. Imaginează-ți că agentul tău are sarcina să scrie o aplicație web complexă, să creeze un Dockerfile pentru ea și să testeze build-ul. Pentru a realiza asta, agentul trebuie să ruleze comenzi Docker. Dacă pur și simplu ai mapa Docker socket-ul sistemului host într-un container standard, agentul ar putea teoretic să lanseze containere privileged direct pe mașina ta host. Docker Sandboxes previn asta rulând un Docker daemon complet izolat chiar în interiorul microVM-ului. Agentul poate să dea build la imagini, să dea pull la dependențe externe și să ruleze nested containers toată ziua. Pentru că discută cu daemonul izolat din interiorul microVM-ului, mediul Docker de pe sistemul tău host rămâne complet neafectat și nepoluat. Când task-ul se termină și sandbox-ul este distrus, daemonul intern și toate imaginile descărcate dispar imediat. Aici devine interesant. Dacă microVM-ul este complet izolat, cum scoți de fapt codul finalizat înapoi? Arhitectura rezolvă asta folosind workspace mounting. Acesta este un mecanism securizat de filesystem passthrough. Când inițializezi sandbox-ul, definești un director specific de pe host care să acționeze ca workspace. Acest singur director este montat în siguranță în microVM. Pe măsură ce agentul scrie cod, rulează teste sau generează assets, le salvează în acest director de workspace. Passthrough-ul sincronizează acele fișiere specifice înapoi în filesystem-ul de pe host în timp real. Agentul livrează output-ul solicitat fără să aibă vreodată acces la restul hard drive-ului tău. Poate să strice orice vrea în interiorul microVM-ului, dar fișierele tale locale rămân neatinse. Ideea principală este că izolarea, în acest context, nu mai înseamnă doar protejarea host-ului de software extern malițios. Este vorba despre a permite în siguranță operațiunile de sistem imprevizibile, highly privileged, pe care un agent autonom trebuie să le facă pentru a fi cu adevărat util. Dacă îți plac aceste episoade și vrei să susții show-ul, poți căuta DevStoriesEU pe Patreon. Asta e tot pentru episodul ăsta. Ne auzim data viitoare!
16

Construirea Echipelor de Agenți AI

4m 01s

Nu te mai baza pe un singur model AI pentru sarcini complexe. Acest episod introduce framework-ul Docker Agent, arătând cum să compui echipe specializate de agenți definite în YAML.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Docker Masterclass, episodul 16 din 18. Îi dai o eroare masivă de aplicație unui singur model AI. Acesta încearcă să țină întreaga arhitectură, log-urile și sintaxa țintă în memorie, toate deodată. La jumătatea drumului, se încurcă și halucinează un fix pentru un fișier complet fără legătură. Un model generic care încearcă să facă totul duce la context overload. Pentru a rezolva probleme complexe în mod fiabil, ai nevoie să construiești echipe de agenți AI. Framework-ul Docker Agent îți permite să definești echipe specializate de agenți AI folosind un simplu fișier de configurare YAML. În loc să scrii un singur system prompt monolitic, împarți workflow-ul în roluri discrete. Structurezi asta ca o ierarhie. Există un root agent care orchestrează workflow-ul și mai mulți sub-agenți care execută task-uri specifice. Asta izolează contextul. Fiecare sub-agent primește doar informațiile de care are nevoie pentru jobul său specific. Ia în considerare un debugging workflow. Ai nevoie de o echipă cu două roluri distincte. În primul rând, un bug investigator care analizează stack trace-urile. În al doilea rând, un fixer care rescrie efectiv codul stricat. Definești întreaga componență a echipei într-un fișier numit docker dash agent dot yml. Începi prin a configura root agent-ul în partea de sus a fișierului. Îi dai un nume, selectezi un language model de bază și oferi system instructions. Root agent-ul acționează ca manager. Responsabilitatea sa principală nu este să rezolve problema direct, ci să delege munca. Instruiești root agent-ul să coordoneze între investigator și fixer pe baza input-urilor pe care le primește. Apoi, definești sub-agenții în același fișier YAML. Declari agentul bug investigator. Îi atribui un model care excelează la reasoning și la citirea log-urilor. Îi dai instrucțiuni stricte să citească doar stack trace-urile, să identifice funcția care pică și să dea output la o scurtă explicație a motivului pentru care a eșuat. Apoi, declari agentul code fixer. Îi poți atribui un model optimizat special pentru code generation. Instrucțiunile sale îi spun strict să ia o funcție care pică și să returneze o versiune corectată. Fără analiză de log-uri, doar code in și code out. Când rulezi această echipă, utilizatorul interacționează doar cu root agent-ul. Îi dai root agent-ului un dump masiv de log-uri de aplicație. Root agent-ul evaluează request-ul și citește descrierile sub-agenților săi disponibili. Acesta determină că bug investigator-ul este agentul potrivit pentru primul pas. Root agent-ul dă mai departe log dump-ul către investigator. Investigatorul procesează zgomotul, găsește un null pointer exception într-o funcție specifică și returnează doar acel detaliu specific. Root agent-ul preia acea informație izolată și o dă mai departe agentului code fixer. Code fixer-ul scrie patch-ul și i-l dă înapoi root manager-ului, care apoi îți returnează rezultatul final, curat. Iată ideea cheie. Code fixer-ul nu vede niciodată stack trace-ul masiv. Vede doar funcția exactă pe care trebuie să o repare. Protejezi context window-ul modelului de coding filtrând zgomotul în prealabil. Prin atribuirea de instrucțiuni specifice și restrânse sub-agenților individuali din fișierul YAML, împiedici modelele să devieze de la task. Root agent-ul se ocupă de secvență, iar sub-agenții se ocupă de execuție. Structurarea ierarhică a agenților te obligă să tratezi AI-ul ca pe o arhitectură de microservicii, atribuind limite stricte pentru lucrurile de care are voie să se ocupe fiecare model în parte. Asta e tot pentru acest episod. Mulțumesc pentru audiție și continuă să construiești!
17

Toolset-uri și Workflow-uri pentru Agenți

3m 37s

Fă-ți agenții AI cu adevărat utili oferindu-le constrângerile potrivite. Află cum să configurezi toolset-uri pentru sistemul de fișiere și să impui workflow-uri structurate de dezvoltare în Docker Agent.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Docker Masterclass, episodul 17 din 18. Un agent AI cu cel mai avansat language model este practic inutil pentru development dacă nu îți poate citi codul sursă sau executa test suite-ul. Fără capabilități externe, doar ghicește sintaxa. Conceptele de toolsets și workflows pentru agenți rezolvă asta acoperind distanța dintre un simplu generator de text și un software engineer capabil. By default, un agent Docker rulează într-un container izolat. Nu are nicio idee ce fișiere există în directorul proiectului tău. Pentru a schimba asta, configurezi array-ul de toolsets în fișierul YAML al agentului tău. Aceste toolsets sunt capabilități pre-împachetate care îi oferă agentului acces direct la host environment. Pentru un agent de development, de obicei injectezi două toolsets principale: acces la filesystem și acces la shell. Acest filesystem toolset îi permite agentului să îți citească directory tree-ul, să deschidă fișiere sursă și să scrie cod înapoi pe disc. Iar shell toolset-ul îi permite agentului să ruleze comenzi în terminal. Fără array-ul de toolsets, agentul tău este prins într-o cutie. Cu el, agentul tău are mâini și ochi. Totuși, să-i dai unui agent mâini și ochi este o rețetă pentru haos dacă îi lipsește disciplina. Un agent nestructurat ar putea modifica un fișier, ar presupune că a funcționat și ar raporta succesul fără să verifice vreodată dacă există erori de sintaxă. Tu controlezi acest comportament folosind blocul instructions din fișierul YAML. Acest bloc nu este un loc pentru sugestii vagi. Este locul unde definești un workflow operațional strict. Cel mai sigur mod de a structura aceste instrucțiuni este să împarți task-urile agentului în patru faze obligatorii: Analyze, Examine, Modify și Validate. Le scrii direct în blocul instructions, spunându-i agentului că trebuie să termine o fază înainte să treacă la următoarea. Prima este Analyze. Agentul citește user prompt-ul pentru a înțelege feature-ul sau bug fix-ul cerut. Următoarea este Examine. Aici, instruiești agentul să folosească filesystem toolset-ul pentru a căuta în codebase-ul tău, a găsi fișierele relevante și a le citi conținutul ca să înțeleagă logica curentă. A treia este Modify. Agentul scrie codul actualizat pe disc. Aici vine partea care contează. A patra fază este Validate. Aici forțezi agentul să-și demonstreze munca folosind shell toolset-ul. Gândește-te la un agent expert în development pe Go. În secțiunea Validate a instrucțiunilor tale, îi ceri explicit agentului să ruleze comanda go test dot slash dot dot dot, urmată de golangci dash lint run. Pentru că agentul are acces la shell, va executa exact acele comenzi. Dacă acel compiler de Go aruncă o eroare de sintaxă, sau dacă un test pică, toolset-ul trimite acel terminal output direct înapoi la agent. Pentru că instrucțiunile tale spun clar că task-ul nu este complet până când validarea nu trece, agentul este forțat să citească eroarea, să se întoarcă la faza Modify, să repare codul și să ruleze testele din nou. Va repeta acest ciclu până când linter-ul este mulțumit și testele trec. Oferindu-i acces la filesystem și la shell, îți faci agentul capabil să scrie software. Dar structurarea instrucțiunilor sale pentru a cere executarea explicită a testelor îți face agentul fiabil. Îi legi tool-urile de un validation loop strict, astfel încât să nu mai fii nevoit niciodată să faci review pe cod stricat. Asta e tot pentru acest episod. Mersi că m-ai ascultat și continuă să construiești!
18

Modele AI în Compose

3m 25s

Tratează-ți LLM-urile locale exact ca pe orice altă dependență a aplicației. Află cum să declari, să configurezi și să asociezi modele AI direct în fișierul tău YAML Docker Compose.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Docker Masterclass, episodul 18 din 18. Aplicația ta depinde de un Large Language Model local. Probabil pornești un inference engine extern, configurezi rețeaua manual și injectezi manual URL-urile de endpoint. Funcționează, dar strică reproductibilitatea izolată a mediului tău. Modelul tău AI este doar o altă dependență și locul lui este în fișierul tău de configurare, chiar lângă baza de date. Exact asta realizează elementul top-level models din Docker Compose. Începând cu versiunea 2.38 de Compose, modelele sunt un concept nativ. Înainte, rularea unui model local însemna să scrii definiții complexe de servicii pentru un inference engine, să expui manual porturi și să configurezi network bridges, astfel încât containerul aplicației tale să poată comunica cu el. Noul block models elimină această fricțiune, tratând modelul AI ca pe o piesă distinctă de infrastructură. Adaugi un block models la nivelul top-level al fișierului tău, la aceeași indentare cu services și volumes. În interior, dai un nume modelului tău. Să folosim ai/smollm2 pentru o aplicație simplă de chat. Sub acest nume, declari identificatorul real al modelului căruia îi faci pull. Tot aici definești și constrângerile hardware și parametrii de engine. Poți seta dimensiunea de context pentru a restricționa utilizarea memoriei. Dacă engine-ul din spate necesită parametri specifici de lansare, îi definești folosind runtime flags. Configurația modelului este izolată și clară. Apoi, faci bind între aplicația ta și model. În interiorul block-ului services, localizezi serviciul aplicației tale de chat și adaugi un array models. Folosind sintaxa scurtă, pur și simplu listezi ai/smollm2. Nu este nevoie să configurezi dependențele manual sau să setezi networking aliases custom. Aici este ideea principală. Când folosești această sintaxă scurtă de binding, Compose preia orchestrarea. El face provision pentru inference engine-ul corect în fundal, pentru a servi modelul specificat. Cel mai important, generează automat environment variables standard și le injectează direct în containerul aplicației tale de chat. Codul tău pornește cu variabile precum OPENAI_BASE_URL deja populate, care pointează perfect către endpoint-ul intern al modelului. Execuți o singură comandă docker compose up. Compose face pull modelului smollm2, configurează engine-ul, pornește serviciul tău de chat și stabilește conexiunea. Fără API keys manuale, fără să ghicești adresele IP interne. Totul este rutat corect out of the box. Te încurajez să explorezi documentația oficială și să încerci să scrii tu însuți unul dintre aceste fișiere. Deoarece asta încheie seria noastră de masterclass, nu ezita să vizitezi devstories dot eu pentru a sugera subiecte pentru ce vom acoperi în continuare. Prin ridicarea modelelor AI la rangul de elemente native în configurația ta, infrastructura ta devine complet declarativă, asigurându-te că versiunea exactă a modelului pe care o așteaptă codul tău este întotdeauna cea care pornește. Asta e tot pentru astăzi. Mulțumesc că m-ai ascultat — du-te și construiește ceva cool.