Mai bine mai târziu decât niciodată. Sau cum am aproape comis o greșeală serioasă neavând suport pentru Dockerfile tradiționale pentru construirea imaginilor aplicației.

Va fi vorba despre — un instrument GitOps care se integrează cu orice sistem CI/CD și asigură gestionarea întregului ciclu de viață al aplicației, permițând:
- începutul și publicarea imaginilor,
- implementarea aplicațiilor în Kubernetes,
- eliminarea imaginilor neutilizate prin politici speciale.
Filozofia proiectului este de a aduna instrumente de nivel jos într-un singur sistem unificat, care să ofere inginerilor DevOps control asupra aplicațiilor. Pe cât posibil, trebuie să fie utilizate utilitarele existente (precum Helm și Docker). Dacă nu există o soluție pentru o anumită problemă, putem crea și menține tot ce este necesar pentru aceasta.
Context: propriul nostru constructor de imagini
Astfel s-a întâmplat cu constructorul de imagini în werf: ne lipsea Dockerfile-ul obișnuit. Dacă ne gândim la istoria proiectului, această problemă s-a manifestat în primele versiuni ale werf (pe atunci cunoscut ca dapp) ).
Necesitatea de a construi aplicații web mici tipice conform următoarei scheme standard:
- instalarea dependențelor de sistem ale aplicației,
- instalarea bibliotecilor de dependență ale aplicației,
- construirea resurselor,
- iar cel mai important - actualizarea rapidă și eficientă a codului în imagine.
- La modificările din fișierele proiectului, constructorul trebuie să genereze rapid un nou strat prin aplicarea unui patch pe fișierele modificate.
- Dacă anumite fișiere s-au schimbat, atunci este necesar să se reconstruiască etapa de dependență corespunzătoare.
- Până în prezent, constructorul nostru are multe alte funcționalități, dar dorințele și impulsurile inițiale au fost acestea.
În general, fără să stăm pe gânduri, ne-am înarmat cu limbajul de programare utilizat
și am pornit la drum - implementând (vezi mai jos) DSL-ul nostru propriu ! Conform cerințelor stabilite, acesta a fost destinat descrierii procesului de construcție pe etape și determinării dependențelor acestor etape în funcție de fișiere. Și a fost completat deconstructorul propriu , care transforma DSL-ul în scopul final - imaginea construită. La început, DSL-ul era în Ruby, iar pe parcursultrecerii la Golang — конфиг нашего сборщика стал описываться в YAML-файле.

Configurația veche pentru dapp pe Ruby

Configurația actuală pentru werf pe YAML
Mecanismul de funcționare al compilatorului s-a schimbat de-a lungul timpului. La început, generam în mod temporar un Dockerfile din configurația noastră, iar apoi am început să rulăm instrucțiuni de compilare în containere temporare și să facem commit.
NB: În prezent, compilatorul nostru, care lucrează cu configurația sa (în YAML) și se numește compilator Stapel, s-a dezvoltat într-un instrument destul de puternic. Descrierea sa detaliată merită articole separate, iar principalele detalii pot fi aflate din .
Conștientizarea problemei
Dar am realizat, deși nu imediat, că am făcut o greșeală: nu am adăugat posibilitatea de a construi imagini printr-un Dockerfile standard și de a le integra în aceeași infrastructură de gestionare completă a aplicației (adică de a construi imagini, a le desfășura și a le curăța). Cum era posibil să creăm un instrument pentru desfășurarea în Kubernetes și să nu implementăm suport pentru Dockerfile, adică metoda standard de descriere a imaginilor pentru cele mai multe proiecte?..
În loc de un răspuns la o astfel de întrebare, oferim soluția sa. Ce să faceți dacă aveți deja un Dockerfile (sau un set de Dockerfile-uri) și doriți să folosiți werf?
NB: Apropo, de ce ați dori să folosiți werf? Principalele funcții se reduc la următoarele:
- ciclul complet de gestionare a aplicației, inclusiv curățarea imaginilor;
- posibilitatea de a gestiona compilarea mai multor imagini dintr-o configurație unică;
- procesul îmbunătățit de desfășurare a charturilor compatibile cu Helm.
Pentru o listă mai completă, puteți consulta .
Așadar, dacă înainte am fi sugerat să rescriem Dockerfile-ul pe configurația noastră, acum spunem cu plăcere: „Permiteți-le werf să construiască Dockerfile-urile dvs.!"
Cum se folosește?
Implementarea completă a acestei funcționalități a apărut în versiunea . Principiul general este simplu: utilizatorul specifică calea către Dockerfile existent în configurația werf, apoi rulează comanda werf build… și totul — werf va construi imaginea. Să luăm un exemplu abstract.
Să declarăm următorul Dockerfile în rădăcina proiectului:
FROM ubuntu:18.04
RUN echo Building ... Și să declarăm werf.yaml, care folosește acest Dockerfile:
configVersion: 1
project: dockerfile-example
---
image: ~
dockerfile: ./Dockerfile Asta e! Rămâne să pornească werf build:

În plus, se poate declara următorul werf.yaml pentru a construi mai multe imagini din diferite Dockerfile-uri:
configVersion: 1
project: dockerfile-example
---
image: backend
dockerfile: ./dockerfiles/Dockerfile-backend
---
image: frontend
dockerfile: ./dockerfiles/Dockerfile-frontend În cele din urmă, se suportă și transmiterea parametrilor suplimentari de construire — cum ar fi --build-arg și --add-host — prin intermediul configurației werf. O descriere completă a configurației imaginii Dockerfile este disponibilă pe .
Cum funcționează?
În procesul de construire, funcționează memoria cache standard a nivelurilor locale în Docker. Cu toate acestea, ceea ce este important este că werf de asemenea integrează configurația Dockerfile în infrastructura sa. Ce înseamnă asta?
- Fiecare imagine construită din Dockerfile constă dintr-un singur stage numit
dockerfile(detalii despre ce sunt stage-urile în werf pot fi citite ). - Pentru stage-ul
dockerfilewerf calculează o semnătură, care depinde de conținutul configurației Dockerfile. Când configurația Dockerfile se schimbă, se schimbă și semnătura etapeidockerfileiar werf inițiază reconstrucția acestei etape cu noua configurație Dockerfile. Dacă semnătura nu se schimbă, werf ia imaginea din cache (detalii despre utilizarea semnăturilor în werf au fost prezentate în ). - Apoi, imaginile construite pot fi publicate cu comanda
werf publish(sauwerf build-and-publish) și utilizate pentru desfășurarea în Kubernetes. Imaginile publicate în Docker Registry vor fi curățate cu ajutoarele standard de curățare werf, adică va avea loc o curățare automată a imaginilor vechi (mai vechi de N zile), a imaginilor legate de ramuri Git inexistente și conform altor politici.
Detalii despre aspectele descrise aici pot fi găsite în documentație:
- ;
- ;
- .
Note și precauții
1. URL extern în ADD nu este suportat
În prezent, utilizarea unui URL extern în directiva ADD. Werf nu va iniția reconstrucția în cazul modificării resursei la URL-ul specificat. Este planificată introducerea acestei funcții în curând.
2. Nu se poate adăuga .git în imagine
În general, adăugarea directorului .git în imagine este o practică proastă și iată de ce:
- Dacă
.gitrămâne în imaginea finală, încălcând principiile : deoarece imaginea finală trebuie să fie asociată cu un singur commit, nu ar trebui să existe posibilitatea de a facegit checkoutun commit aleator. -
.gitcrește dimensiunea imaginii (repozitoriul poate fi mare deoarece a fost adăugat anterior fișiere mari, iar apoi s-au șters). Dimensiunea work-tree, legată doar de un anumit commit, nu va depinde de istoricul operațiunilor în Git. În același timp, adăugarea și apoi eliminarea.gitDin imaginea finală nu se va activa: imaginea va căpăta oricum un strat suplimentar — așa funcționează Docker. - Docker poate iniția o reconstituire suplimentară, chiar dacă se compilează același commit, dar din work-tree-uri diferite. De exemplu, GitLab creează directorii separate clonat.
/home/gitlab-runner/builds/HASH/[0-N]/yourprojectcând compilarea paralelă este activată. Reconstituirea suplimentară va fi legată de faptul că directorul.gitdiferențiază versiuni diferite clonat ale aceluiași repository, chiar dacă se compilează același commit.
Ultimul punct are consecințe și atunci când utilizați werf. Werf necesită ca cache-ul construit să fie prezent în timpul rulării unor comenzi (de exemplu, werf deploy). În timpul rularii acestor comenzi, werf calculează semnăturile stadiilor pentru imaginile specificate în werf.yaml, și acestea trebuie să fie în cache-ul de compilare — altfel, comanda nu va putea continua. Dacă semnătura stadiilor depinde de conținutul .git, atunci obținem un cache instabil la modificări în fișiere nerelevante, iar werf nu va putea ierta o astfel de greșeală (mai multe detalii pot fi găsite în ).
În general adăugarea doar a fișierelor necesare prin instrucțiunea ADD în orice caz, crește eficiența și fiabilitatea acestuia Dockerfile, precum și îmbunătățește stabilitatea cache-ului, construit pe baza acestuia Dockerfile, la modificările nerelevante din Git.
Rezultatul
Calea noastră inițială cu scrierea propriului builder pentru nevoile specifice a fost grea, cinstită și dreaptă: în loc să folosim soluții temporare peste Dockerfile-ul standard, ne-am scris propria soluție cu o sintaxă personalizată. Și aceasta a avut avantajele ei: builder-ul Stapel își îndeplinește excelent sarcina.
Cu toate acestea, în procesul de scriere a propriului builder, am omis să suportăm deja existenții Dockerfile. Acum această lipsă este corectată, iar pe viitor ne propunem să dezvoltăm suportul pentru Dockerfile, împreună cu builder-ul nostru personalizat Stapel pentru compilarea distribuită și pentru compilarea utilizând Kubernetes (adică compilarea pe runneri în interiorul Kubernetes, așa cum se face în kaniko).
Așadar, dacă ai câteva Dockerfile-uri adunate pe undeva... încercați !
P.S. Lista de documentație pe subiect
- ;
- ;
- ;
- ;
- ;
- ;
- .
Citiți și în blogul nostru: „».
Sursa: habr.com
