Mi az ismételhető build?
A Determinisztikus Build vagy Reproducible Build kissé eltérőek, de ebből a cikkből ugyanaznak érthetőek.
A reprodukálható építések a következőkre vonatkoznakA build folyamat többszöri végrehajtása ugyanazzal a bemenettel és építési környezettel pontosan ugyanazt az eredményt hozhatja。 Ez a technológia fontos a szoftverfejlesztéshez, terjesztéshez és biztonsági ellenőrzéshez.
Egy build reprodukálható, ha pontosan ugyanazt a kimenetet adja, függetlenül attól, hogy mikor és hol futtatják. Függetlenül attól, hogy melyik számítógépen futsz, milyen napszakban vagy milyen külső szolgáltatásokat érsz el a hálózaton keresztül, a reprodukálható buildek ugyanazt a bájtról bájtora adják elő. Ez nagyszerű mind a fejlesztéshez (mert a reprodukálható buildeket könnyű megosztani különböző fejlesztői eszközök között), mind a gyártásra (mert könnyű biztosítani, hogy a reprodukálható buildek eredményeit nem manipulálták – csak futtasd újra a saját gépeden, és ellenőrizd, hogy az eredmények következetesek!). nagyon hasznosak.
A három ismételhető építkezés oszlopa
1. oszlop: Ismételhető buildek
A build ismételhetőség azt jelenti, mi történik magával a géppel. Feltételezve, hogy a build inputjaink elérhetők, és semmi sem változik a körülöttünk lévő világban, ugyanazt a kimenetet adja-e a buildünk, ha ismételjük?
Determinisztikus telepítési terv
Az első, legegyszerűbb és legnyilvánvalóbb követelmény egy ismételhető építésben a determinisztikus függőségi telepítési terv.
A legtöbb nyelven ez annyi egyszerű, mint egy zárt fájl bekapcsolása. A modern build eszközök gyakran lehetővé teszik, hogy a projektek közvetlen függőségi követelményeket feltételekként fejezzék ki, majd ezeket a korlátokat megoldják, hogy telepítési tervet (függőségnevek és verziópárok listája) generáljanak. Sok ilyen eszköz zárfájlokat generál sorozatos telepítési tervekhez is. A fejlesztők ezeket a zárfájlokat verziókezelésnek is benyújthatják, hogy a jövőbeli verziók ugyanazokat a függőségi neveket és verziókat használják.
Fontos megjegyezni, hogy magában a függőségi buildben is szükségünk van determinisztikára (nem csak verzióválasztásnál), és egy determinisztikus telepítési terv ezt nem teszi lehetővé!
Determinisztikus konstrukció
Miután tudjuk, mit kell építeni, maga a build (beleértve a saját kódunkat és a függőségi kódot is) valójában determinisztikusnak kell lennie.
Ez valójában nem feltétlenül jelent problémát olyan projektek esetében, amelyeknek nincs fordítási lépése! Például egy Node projekt, amely minden függőséget tartalmaz, tiszta JavaScript, és nem szükséges további munka a hatékony determinisztika eléréséhez.
Olyan projektek esetén, amelyek tartalmaznak fordítási vagy fordítási (forrásból forrásra fordítás) lépéseket, a determinizmus biztosítása messze a legnehezebb része egy reprodukálható build építésének. A fordítási folyamat implicit módon számos módon vezethet be a nem-determinizmust, például:
- A Turing-teljes programépítési szkriptek képesek bármikor módosítani a fordított kimenetet.
- Telepítés utáni szkriptek, amelyek futtatható fájlrendszer lekérdezésekre vagy hálózati hívásokra támaszkodnak.
- C kötés egy rendszerhez telepített csomaghoz, ahol különböző fejlécekkel rendelkező rendszerek kötelékei eltérő kimenetet eredményezhetnek.
- Lépések egy olyan fájl építéséhez, amely a verziókezelésen kívül olvasható.
- Építs lépéseket az időbélyegek generálásához a rendszer idején keresztül.
- Olyan függőségek létrehozásának lépései, amelyek nem szerepelnek a hálózati letöltési telepítési tervben (például NPM függőség letöltése a GitHubból egy C-bound gyorsítótáros bináris build esetén).
- Változtasd meg a viselkedést a jelenleg beállított környezeti változó alapján, de ne küldj be buildet a környezeti változó konfigurációval.
Nem mindegyik viselkedés okoz bizonytalanságot, ha helyesen beállítják, de a build folyamat megfelelő konfigurálása bonyolult és nehéz lehet. Például elolvashatod ezt a blogbejegyzést a Chromium build-ek bizonytalanságáról. Sok ilyen probléma enyhíthető a helyi építési környezet szabályozásával, amelyről a következő szakaszban tárgyalunk.
2. pillér: Megváltoztathatatlan környezet
Még ismételhető buildeknél is ügyelnünk kell arra, hogy a build inputok ne változzanak. Gyakran ez azt jelenti, hogy biztosítani akarjuk, hogy egy változatlan pillanatképre építsünk a környezetünkről.
Megváltoztathatatlan helyi környezet
Ahogy fentebb tárgyaltuk, a build bizonytalanság egyik gyakori forrása azokra a "függőségekre" támaszkodunk, amelyeket a build eszköz nem foglal le. A C-bound rendszerkönyvtárak a leggyakoribb példák, de más helyi környezeti tényezők, mint például a környezeti változók beállításai és a verzióvezérlés hatáskörén kívüli fájlok is befolyásolhatják a buildet.
Egy egyszerű módja ennek a problémának az enyhítésének, ha a build ismert, változatlan konténerben futtatja le. Például egy konténer futóidő, mint a Docker, biztosítja, hogy mindenki ugyanazt a rendszerfüggőséget, ugyanazokat a környezeti változókat használja, és ugyanazon fájlrendszeren futjon. Emellett könnyű ellenőrizni, hogy a konténer tartalma egyezik-e egy ismert jó építésű konténerrel, és szükség esetén a konténer könnyen eltávolítható a ismert jó képről és újraalkotható.
Fontos megjegyezni, hogy nagyon világosan fogalmazunk az ismert konténerek vagy ismert konténer képek tekintetében. Nem elég, ha csak beküldünk egy Dockerfile-t! Miért? Mert maga a Dockerfile nem írja le teljesen reprodukálható Docker képek építési folyamatát, mert ezek nem futnak megváltoztathatatlan globális környezetben.
Megváltoztathatatlan globális környezet
A build rendszerek gyakran interakcióba lépnek külső szolgáltatásokkal, hogy elvégezzék a verziófelbontást és a függőségi letöltéseket. De a külső szolgáltatások gyakran változnak.
Ha ma futtatod az apt install nodejs-t, más eredményt adsz, mint tavaly, és valószínűleg jövőre is más eredményeket kapsz. Ezért nem tudják maguk a Dockerfiles leírni a reprodukálható buildeket – ha ugyanazt a Dockerfile-t különböző időpontokban futtatjuk, akkor különböző build kimeneteket eredményez!
Az egyszerű megoldás az, hogy a build konfigurálása lehetőség szerint pontos verziót (ideális esetben egy pontos tartalom hash-et is), hogy a jövőbeli verziók ugyanazt a verziót használják, mint a jelenlegi verzió. De a külső szolgáltatások váratlanul is megváltoztathatják viselkedésüket – egy igazán pesszimista, reprodukálható build belső képet futtat a lehető legtöbb hálózati erőforrásával.
3. pillér: Erőforrások elérhetősége
Tegyük fel, hogy a testfelépítésünk ismételhető, és a világ a lábunk alatt nem változik. Most már csak hozzáférés kell a build inputhoz. Egyszerűnek tűnik, ugye? Kút......
A nyilvántartás néha meghibásodik
A legtöbb Node fejlesztő legalább egy NPM-kiesést tapasztalt, amely során az építési csővezeték nem gyorsítótározza vagy tükrözi az NPM csomagokat. Sok Node fejlesztő tapasztalt baloldali pad- és hamisító eltávolításokat is, amelyek súlyosan károsították az NPM ökoszisztémát, és gyakorlatilag kimaradáshoz vezettek.
Az egyetlen megbízható módja az ilyen build-szünetek csökkentésének, ha saját csomagregiszter tükört futtatsz. Ha külső szolgáltatások nem elérhetők, a kép online maradhat; Amikor a hivatalos regiszter törli a régi csomagot, a tükör továbbra is szolgáltatásokat nyújthat. Ugyanez az elv érvényes más távoli szolgáltatásokra is: hacsak nem futtatod a saját imagodat, egy build pipeline elérhetősége csak a szolgáltatásai elérhetőségével egyeztethető.
A szolgáltatási kép futtatása mindig kényes kompromisszum. Egyrészt az NPM-hez hasonló regisztereknek dedikált mérnöki és műveleti csapatai vannak, akik rendelkeznek a szakértelemmel ahhoz, hogy ezeket a rendszereket online tartsák. Másrészt sokkal könnyebb egy kis képet futtatni egy kis függőségi készlethez, mint minden NPM képet futtatni. A szolgáltatás specifikációi alapján kell tükröződő döntéseket hoznod, figyelembe véve a korábbi külső szolgáltatások megbízhatóságát, valamint a csapatod építési elérhetőségét és személyzeti igényeit.
A beszállítók biztosítják a maximális elérhetőséget
Egy egyszerű módja annak, hogy biztosítsd a projekt függőségeinek maximális elérhetőségét, ha hozzáadod őket a beszállítóhoz. A legtöbb csomagkezelő támogatja valamilyen "vendoringet", ami azt jelenti, hogy a függőség forráskódját verziókezelésben tároljuk, amely együtt létezik a forráskódunkkal. Például a Node-ban ez úgy tűnhet, mintha node_modules forráskontrollra köteleznénk meg.
Bár ez a megoldás nem tökéletes (attól függően, hogyan van beépítve a beszállítód és a projekted, ami nagy terhet róhat a verzióvezérlésre), gyakran a legegyszerűbb és legegyszerűbb megoldás a maximális elérhetőség érdekében.
Utalás:
A hiperlink bejelentkezés látható.
A hiperlink bejelentkezés látható. |