Hva er en repeterbar build?
Deterministisk build eller reproducable build er litt forskjellige, men de kan forstås som det samme som i denne artikkelen.
Reproduserbare bygg refererer tilFlere kjøringer av byggeprosessen med samme input og byggemiljø kan gi nøyaktig de samme resultatene。 Denne teknologien er viktig for programvareutvikling, distribusjon og sikkerhetsvalidering.
Et bygg er reproduserbart hvis det gir nøyaktig samme utgang uavhengig av når og hvor det kjøres. Uansett hvilken datamaskin du kjører på, hvilket tidspunkt på dagen, og hvilke eksterne tjenester du får tilgang til over nettverket, produserer reproduserbare bygg samme byte-for-byte utdata. Dette er flott både for utvikling (fordi reproduserbare bygg er lett å dele på tvers av ulike utviklerenheter) og produksjon (fordi det er lett å sikre at resultatene av reproduserbare bygg ikke har blitt tuklet med – bare kjør bygget på nytt på din egen maskin og sjekk at resultatene er konsistente!). er veldig nyttige.
De tre pilarene i repeterbare bygg
Pilar 1: Repeterbare bygg
Byggerepeterbarhet refererer til hva som skjer med selve byggemaskinen. Forutsatt at byggeinputene våre er tilgjengelige, og ingenting endrer seg i verden rundt oss, produserer bygget vårt samme resultat når det gjentas?
Deterministisk installasjonsplan
Det første, enkleste og mest åpenbare kravet i en repeterbar bygging er en deterministisk avhengighetsinstallasjonsplan.
I de fleste språk er det så enkelt som å sjekke inn en låst fil. Moderne byggeverktøy lar ofte prosjekter uttrykke direkte avhengighetskrav som begrensninger, og deretter løse disse begrensningene for å generere en installasjonsplan (en liste over avhengighetsnavn og versjonspar som skal installeres). Mange av disse verktøyene genererer også låsefiler for serialiserte installasjonsplaner. Utviklere kan sende disse låsefilene til versjonskontroll slik at fremtidige versjoner bruker de samme avhengighetsnavnene og versjonene.
Merk at vi også trenger deterministisk i selve avhengighetsbygget (ikke bare versjonsvalg), og en deterministisk installasjonsplan lar oss ikke oppnå dette!
Deterministisk konstruksjon
Når vi vet hva vi skal bygge, må selve bygget vårt (inkludert vår egen kode og avhengighetskoden) faktisk være deterministisk.
Dette er kanskje ikke et problem for prosjekter uten kompileringssteg! For eksempel er et Node-prosjekt med alle avhengigheter ren JavaScript, og det kreves ingen ekstra arbeid for å oppnå effektiv deterministisitet.
For prosjekter som inkluderer kompilerings- eller oversettelsessteg (kilde-til-kilde-kompilering), er det klart vanskeligste å sikre determinisme i å bygge en reproduserbar build. Kompilasjonsprosessen kan implisitt introdusere ikke-determinisme på flere måter, inkludert:
- Turing-komplette programbygg-skript kan endre den kompilerte utdataen etter eget ønske.
- Etterinstallasjonsskript som er avhengige av kjørbare filsystemoppslag eller nettverkskall.
- C-binding til en systeminstallert pakke hvor bindings på ulike systemer med forskjellige headere kan gi ulike utganger.
- Trinn for å bygge en fil som leses utenfor versjonskontroll.
- Bygg steg for å generere tidsstempler ved hjelp av systemtid.
- Trinn for å bygge avhengigheter som ikke er uttrykt i installasjonsplanen for nedlasting av nettverket (for eksempel last ned en NPM-avhengighet fra GitHub for en bufret binær build som er C-bundet).
- Endre atferden basert på den nåværende satt miljøvariabelen, men ikke send inn en build med miljøvariabelkonfigurasjonen.
Ikke alle disse atferdene fører nødvendigvis til usikkerhet når de settes opp riktig, men riktig konfigurasjon av byggeprosessen kan være komplekst og vanskelig. For eksempel kan du lese dette blogginnlegget om usikkerhet i Chromium-bygg. Mange av disse problemene kan dempes ved å kontrollere det lokale byggemiljøet, som vi vil diskutere i neste avsnitt.
Søyle 2: Uforanderlig miljø
Selv med repeterbare builds må vi sørge for at build-inputene ikke endres. Ofte betyr dette at vi vil sørge for at vi bygger på et uforanderlig øyeblikksbilde av omgivelsene våre.
Uforanderlig lokalmiljø
Som vi diskuterte ovenfor, er en vanlig kilde til byggeusikkerhet å stole på «avhengigheter» som ikke fanges opp av byggeverktøyet. C-bundne systembiblioteker er de vanligste eksemplene, men andre lokale miljøfaktorer som innstillinger av miljøvariabler og filer utenfor versjonskontrollens område kan også påvirke byggingen.
En enkel måte å redusere dette problemet på er å kjøre bygget i en kjent, uforanderlig container. For eksempel hjelper en containerkjøring som Docker med å sikre at alle bruker de samme systemavhengighetene, de samme miljøvariablene, og kjører på samme filsystem. I tillegg er det enkelt å verifisere at innholdet i containeren samsvarer med en kjent god byggecontainer, og om nødvendig kan containeren enkelt fjernes helt fra det kjente gode bildet og gjenskapes.
Merk at vi er veldig tydelige på kjente beholdere eller kjente containerbilder. Det er ikke nok å bare sende inn en Dockerfile! Hvorfor? Fordi Dockerfile i seg selv ikke beskriver en fullt reproduserbar byggeprosess for Docker-bilder, fordi de ikke kjører i et uforanderlig globalt miljø.
Uforanderlig globalt miljø
Byggesystemer samhandler ofte med eksterne tjenester for å utføre oppgaver som versjonsoppløsning og nedlastinger av avhengigheter. Men eksterne tjenester endres ofte.
Å kjøre apt install nodejs i dag vil gi deg andre resultater enn i fjor, og sannsynligvis vil neste år også gi andre resultater. Derfor kan ikke Dockerfiles selv beskrive reproduserbare bygg – å kjøre samme Dockerfile på forskjellige tidspunkter vil gi forskjellige byggeresultater!
Den enkle løsningen her er å konfigurere bygget når det er mulig, og spesifisere en eksakt versjon (helst også en eksakt innholdshash) slik at fremtidige bygg bruker samme versjon som den nåværende versjonen. Men eksterne tjenester kan også endre sin atferd uventet – en virkelig pessimistisk reproduserbar build kjører et internt image med så mange av sine nettverksressurser som mulig.
Pilar 3: Ressurstilgjengelighet
La oss si at bygget vårt er repeterbart og verden under føttene våre ikke endrer seg. Alt vi trenger nå er tilgang til byggeinput. Det virker enkelt, ikke sant? Brønn......
Registeret feiler noen ganger
De fleste Node-utviklere har opplevd minst ett NPM-utfall, hvor byggepipelinen uten caching eller speiling av NPM-pakker blir forstyrret. Mange Node-utviklere har også opplevd fjerning av venstre-pad og falske, noe som har skadet NPM-økosystemet alvorlig og i praksis utgjort et strømbrudd.
Den eneste pålitelige måten å redusere slike byggebrudd på, er å kjøre ditt eget pakkeregister-speil. Når eksterne tjenester ikke er tilgjengelige, kan bildet forbli online; Når det offisielle registeret sletter den gamle pakken, kan speilet fortsette å levere tjenester. Det samme prinsippet gjelder for andre eksterne tjenester: med mindre du kjører ditt eget bilde, er tilgjengeligheten til en byggepipeline bare sammenlignbar med tilgjengeligheten til dens tjenester.
Å velge å kjøre et servicebilde er alltid en delikat avveining. På den ene siden har registre som NPM dedikerte ingeniør- og driftsteam som har ekspertisen til å holde disse systemene online. På den annen side er det mye enklere å kjøre et lite bilde for et lite sett med avhengigheter enn å kjøre alle NPM-bilder. Du bør ta speilbeslutninger basert på detaljene i hver tjeneste, med hensyn til påliteligheten til historiske eksterne tjenester og teamets tilgjengelighet og bemanningsbehov.
Leverandører sikrer maksimal tilgjengelighet
En enkel måte å sikre maksimal tilgjengelighet av prosjektets avhengigheter på, er å legge dem til leverandøren din. De fleste pakkebehandlere støtter en form for «leverandør», noe som betyr at i stedet for å stole på nedlastinger fra eksterne tjenester, lagrer vi avhengighetskildekoden i versjonskontroll, og sameksisterer med kildekoden vår. For eksempel kan dette i Node se ut som å committe node_modules til kildekontroll.
Selv om denne løsningen ikke er perfekt (avhengig av hvordan leverandøren og prosjektet ditt er satt opp, noe som kan legge mye press på versjonskontrollen din), er det ofte den enkleste og enkleste løsningen for maksimal tilgjengelighet.
Referanse:
Innloggingen med hyperkoblingen er synlig.
Innloggingen med hyperkoblingen er synlig. |