Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

En tilnærming IaC (Infrastructure as Code) består ikke bare av koden som er lagret i depotet, men også av menneskene og prosessene som omgir denne koden. Er det mulig å gjenbruke tilnærminger fra programvareutvikling til infrastrukturstyring og beskrivelse? Det vil være en god idé å ha denne ideen i bakhodet mens du leser artikkelen.

Angielski versjon

Dette er en utskrift av min forestillingerDevopsConf 2019-05-28.

Lysbilder og videoer

Infrastruktur som bash-historie

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Tenk deg at du kommer til et nytt prosjekt, og de sier til deg: «vi har Infrastruktur som kode". I virkeligheten viser det seg Infrastruktur som bash-historie eller for eksempel Dokumentasjon som bash-historie. Dette er en veldig reell situasjon, for eksempel ble en lignende sak beskrevet av Denis Lysenko i en tale Hvordan erstatte hele infrastrukturen og begynne å sove godt, fortalte han hvordan de fikk en sammenhengende infrastruktur for prosjektet fra bash-historien.

Med litt lyst kan vi si det Infrastruktur som bash-historie dette er som kode:

  1. reproduserbarhet: Du kan ta bash-historikk, kjøre kommandoene derfra, og du kan forresten få en fungerende konfigurasjon som en utgang.
  2. versjonering: du vet hvem som kom inn og hva de gjorde, igjen, det er ikke et faktum at dette vil føre deg til en fungerende konfigurasjon ved utgangen.
  3. historie: historien om hvem som gjorde hva. bare du vil ikke kunne bruke den hvis du mister serveren.

Hva du skal gjøre?

Infrastruktur som kode

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Selv en så merkelig sak som Infrastruktur som bash-historie du kan trekke den i ørene Infrastruktur som kode, men når vi ønsker å gjøre noe mer komplisert enn den gode gamle LAMP-serveren, vil vi komme til den konklusjonen at denne koden på en eller annen måte må modifiseres, endres, forbedres. Deretter vil vi vurdere parallellene mellom Infrastruktur som kode og programvareutvikling.

TØRKE

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

På et utviklingsprosjekt for lagringssystem var det en deloppgave konfigurer SDS med jevne mellomrom: vi slipper en ny utgivelse - den må rulles ut for videre testing. Oppgaven er ekstremt enkel:

  • logg inn her via ssh og utfør kommandoen.
  • kopier filen dit.
  • korriger konfigurasjonen her.
  • starte tjenesten der
  • ...
  • PROFITT!

For den beskrevne logikken er bash mer enn nok, spesielt i de tidlige stadiene av prosjektet, når det bare starter. Dette det er ikke ille at du bruker bash, men over tid kommer det forespørsler om å distribuere noe lignende, men litt annerledes. Det første du tenker på er copy-paste. Og nå har vi allerede to veldig like manus som gjør nesten det samme. Over tid vokste antallet skript, og vi ble møtt med det faktum at det er en viss forretningslogikk for å distribuere en installasjon som må synkroniseres mellom ulike skript, dette er ganske komplisert.

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Det viser seg at det er en slik praksis som DRY (Ikke gjenta deg selv). Tanken er å gjenbruke eksisterende kode. Det høres enkelt ut, men vi kom ikke til dette med en gang. I vårt tilfelle var det en banal idé: å skille konfigurasjoner fra skript. De. forretningslogikk for hvordan installasjonen distribueres separat, konfigureres separat.

SOLID for CFM

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Over tid vokste prosjektet og naturlig fortsettelse var fremveksten av Ansible. Hovedårsaken til utseendet er at det er ekspertise på laget og at bash ikke er designet for kompleks logikk. Ansible begynte også å inneholde kompleks logikk. For å forhindre at kompleks logikk blir til kaos, finnes det prinsipper for kodeorganisering i programvareutvikling FAST For eksempel reiste Grigory Petrov i rapporten "Hvorfor trenger en IT-spesialist et personlig merke" spørsmålet om at en person er utformet på en slik måte at det er lettere for ham å operere med noen sosiale enheter, i programvareutvikling disse er objekter. Hvis vi kombinerer disse to ideene og fortsetter å utvikle dem, vil vi merke at vi også kan bruke FAST for å gjøre det lettere å vedlikeholde og modifisere denne logikken i fremtiden.

Prinsippet om enkelt ansvar

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Hver klasse utfører kun én oppgave.

Du trenger ikke å blande kode og lage monolitiske guddommelige spaghettimonstre. Infrastrukturen bør bestå av enkle murstein. Det viser seg at hvis du deler Ansible-spilleboken i små biter, leser Ansible-roller, så er de lettere å vedlikeholde.

Det åpne lukkede prinsippet

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Åpent/lukket prinsipp.

  • Åpen for utvidelse: betyr at oppførselen til en enhet kan utvides ved å opprette nye enhetstyper.
  • Lukket for endring: Som et resultat av utvidelse av atferden til en enhet, bør ingen endringer gjøres i koden som bruker disse enhetene.

Til å begynne med distribuerte vi testinfrastrukturen på virtuelle maskiner, men på grunn av at forretningslogikken for utrullingen var atskilt fra implementeringen, la vi utrulling til baremetall uten problemer.

Liskov-substitusjonsprinsippet

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Barbara Liskovs substitusjonsprinsipp. objekter i et program må kunne erstattes med forekomster av deres undertyper uten å endre riktig utførelse av programmet

Hvis du ser bredere på det, er det ikke et trekk ved et bestemt prosjekt som kan brukes der FAST, det handler generelt om CFM, for eksempel på et annet prosjekt er det nødvendig å distribuere en bokset Java-applikasjon på toppen av forskjellige Java, applikasjonsservere, databaser, OS, etc. Ved å bruke dette eksemplet vil jeg vurdere ytterligere prinsipper FAST

I vårt tilfelle er det en avtale i infrastrukturteamet om at hvis vi har installert rollen imbjava eller oraclejava, så har vi en java binær kjørbar. Dette er nødvendig pga Oppstrømsroller avhenger av denne oppførselen de forventer java. Samtidig lar dette oss erstatte en java-implementering/versjon med en annen uten å endre applikasjonsdistribusjonslogikken.

Problemet her ligger i at det er umulig å implementere dette i Ansible, som følge av at noen avtaler dukker opp innad i teamet.

Grensesnittsegregeringsprinsippet

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Prinsipp for grensesnittseparasjon: «Mange klientspesifikke grensesnitt er bedre enn ett generellt grensesnitt.

Til å begynne med prøvde vi å legge all variasjonen til applikasjonsdistribusjon i én Ansible-håndbok, men det var vanskelig å støtte, og tilnærmingen når vi har et eksternt grensesnitt spesifisert (klienten forventer port 443), så kan en infrastruktur settes sammen fra individuelle murstein for en spesifikk implementering.

Avhengighetsinversjonsprinsippet

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Prinsippet om avhengighetsinversjon. Moduler på høyere nivåer bør ikke være avhengige av moduler på lavere nivåer. Begge typer moduler må avhenge av abstraksjoner. Abstraksjoner bør ikke avhenge av detaljer. Detaljer må avhenge av abstraksjoner.

Her vil eksemplet være basert på et antimønster.

  1. En av kundene hadde en privat sky.
  2. Vi bestilte virtuelle maskiner inne i skyen.
  3. Men på grunn av skyens natur var applikasjonsdistribusjon knyttet til hvilken hypervisor VM var på.

De. Programdistribusjonslogikk på høyt nivå strømmet med avhengigheter til lavere nivåer av hypervisoren, og dette betydde problemer ved gjenbruk av denne logikken. Ikke gjør det på denne måten.

Interaksjon

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Infrastruktur som kode handler ikke bare om kode, men også om forholdet mellom kode og mennesker, om interaksjoner mellom infrastrukturutviklere.

Bussfaktor

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

La oss anta at du har Vasya på prosjektet ditt. Vasya vet alt om infrastrukturen din, hva vil skje hvis Vasya plutselig forsvinner? Dette er en veldig reell situasjon, fordi han kan bli påkjørt av en buss. Noen ganger skjer det. Hvis dette skjer og kunnskap om koden, dens struktur, hvordan den fungerer, utseende og passord ikke er distribuert mellom teamet, kan du støte på en rekke ubehagelige situasjoner. For å minimere disse risikoene og distribuere kunnskap i teamet, kan du bruke ulike tilnærminger

Pardevopsing

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Det er ikke sånn som en spøk, at administratorene drakk øl, endret passord og en analog av parprogrammering. De. to ingeniører setter seg ned ved én datamaskin, ett tastatur og begynner å sette opp infrastrukturen din sammen: sette opp en server, skrive en Ansible-rolle osv. Det høres fint ut, men det fungerte ikke for oss. Men spesielle tilfeller av denne praksisen fungerte. En ny medarbeider har kommet, mentoren hans tar på seg en reell oppgave sammen med ham, jobber og overfører kunnskap.

Et annet spesielt tilfelle er en hendelsesanrop. Under et problem samles en gruppe av de på vakt og de involverte, en leder utnevnes, som deler skjermen sin og gir uttrykk for tankerekken. Andre deltakere følger lederens tanker, spionerer på triks fra konsollen, kontrollerer at de ikke har gått glipp av en linje i loggen, og lærer nye ting om systemet. Denne tilnærmingen fungerte oftere enn ikke.

Kode anmeldelse

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Subjektivt sett var det mer effektivt å spre kunnskap om infrastrukturen og hvordan den fungerer ved å bruke kodegjennomgang:

  • Infrastrukturen er beskrevet med kode i depotet.
  • Endringer skjer i en egen gren.
  • Under en sammenslåingsforespørsel kan du se deltaet til endringer i infrastrukturen.

Høydepunktet her var at anmelderne ble plukket ut én etter én, etter en tidsplan, d.v.s. med en viss grad av sannsynlighet vil du klatre inn i et nytt stykke infrastruktur.

Kodestil

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Over tid begynte krangling å dukke opp under anmeldelser, fordi... anmeldere hadde sin egen stil og rotasjonen av anmeldere stablet dem med forskjellige stiler: 2 mellomrom eller 4, camelCase eller snake_case. Det var ikke mulig å gjennomføre dette med en gang.

  • Den første ideen var å anbefale å bruke linter, alle er tross alt ingeniører, alle er smarte. Men forskjellige redaktører, OS, er ikke praktiske
  • Dette utviklet seg til en bot som skrev til slakk for hver problematiske commit og festet linter-utgangen. Men i de fleste tilfeller var det viktigere ting å gjøre, og koden forble ufiksert.

Green Build Master

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Tiden går, og vi har kommet til den konklusjonen at forpliktelser som ikke består visse prøver ikke kan slippes inn i masteren. Voila! Vi oppfant Green Build Master, som har vært praktisert innen programvareutvikling i lang tid:

  • Utbygging pågår i en egen gren.
  • Tester kjører på denne tråden.
  • Hvis testene mislykkes, kommer ikke koden inn i masteren.

Å ta denne avgjørelsen var veldig smertefullt, fordi... forårsaket mye kontrovers, men det var verdt det, fordi. Anmeldelser begynte å motta forespørsler om fusjoner uten forskjeller i stil, og over tid begynte antallet problemområder å avta.

IaC-testing

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

I tillegg til stilsjekking kan du bruke andre ting, for eksempel for å sjekke at infrastrukturen din faktisk kan distribueres. Eller sjekk at endringer i infrastruktur ikke vil føre til tap av penger. Hvorfor kan dette være nødvendig? Spørsmålet er komplekst og filosofisk, det er bedre å svare med en historie om at det på en eller annen måte var en auto-scaler på Powershell som ikke sjekket grensebetingelsene => flere VM-er ble opprettet enn nødvendig => klienten brukte mer penger enn planlagt. Dette er ikke veldig hyggelig, men det ville være fullt mulig å fange opp denne feilen på tidligere stadier.

Man kan spørre seg, hvorfor gjøre kompleks infrastruktur enda mer kompleks? Tester for infrastruktur, akkurat som for kode, handler ikke om forenkling, men om å vite hvordan infrastrukturen din skal fungere.

IaC-testpyramide

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

IaC-testing: Statisk analyse

Hvis du distribuerer hele infrastrukturen på en gang og sjekker at den fungerer, kan du oppleve at det tar mye tid og krever mye tid. Derfor må grunnlaget være noe som fungerer raskt, det er mye av det, og det dekker mange primitive steder.

Bash er vanskelig

La oss se på et trivielt eksempel. velg alle filene i gjeldende katalog og kopier til et annet sted. Det første som kommer til tankene:

for i in * ; do 
    cp $i /some/path/$i.bak
done

Hva om det er et mellomrom i filnavnet? Vel, ok, vi er smarte, vi vet hvordan vi bruker anførselstegn:

for i in * ; do cp "$i" "/some/path/$i.bak" ; done

Bra gjort? Nei! Hva om det ikke er noe i katalogen, dvs. globbing vil ikke fungere.

find . -type f -exec mv -v {} dst/{}.bak ;

Godt gjort nå? Nei... Glemte hva som kan stå i filnavnet n.

touch x
mv x  "$(printf "foonbar")"
find . -type f -print0 | xargs -0 mv -t /path/to/target-dir

Statiske analyseverktøy

Problemet fra forrige trinn kunne fanges opp når vi glemte sitatene, for dette er det mange rettsmidler i naturen Shellcheck, generelt er det mange av dem, og mest sannsynlig kan du finne en linter for stabelen din under IDE.

Språk
Tool

bash
Shellcheck

Rubin
RuboCop

python
pylint

ansible
Ansible Lint

IaC-testing: enhetstester

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Som vi så fra forrige eksempel, er linters ikke allmektig og kan ikke peke ut alle problemområdene. Videre, analogt med testing i programvareutvikling, kan vi huske enhetstester. Det du umiddelbart tenker på er shunit, junit, rspec, spørsmål. Men hva skal man gjøre med ansible, kokk, saltstack og andre som dem?

Helt i begynnelsen snakket vi om FAST og at vår infrastruktur skal bestå av små murstein. Deres tid er kommet.

  1. Infrastrukturen er delt inn i små klosser, for eksempel Ansible-roller.
  2. En eller annen form for miljø er distribuert, enten det er docker eller en VM.
  3. Vi bruker vår Ansible-rolle på dette testmiljøet.
  4. Vi sjekker at alt fungerte som forventet (vi kjører tester).
  5. Vi bestemmer ok eller ikke ok.

IaC-testing: Verktøy for enhetstesting

Spørsmål, hva er tester for CFM? Du kan ganske enkelt kjøre skriptet, eller du kan bruke ferdige løsninger for dette:

CFM
Tool

Ansible
Testinfra

Chef
Insp

Chef
Serverspes

saltstabel
Goss

Eksempel for testinfra, sjekke at brukere test1, test2 eksisterer og er i en gruppe sshusers:

def test_default_users(host):
    users = ['test1', 'test2' ]
    for login in users:
        assert host.user(login).exists
        assert 'sshusers' in host.user(login).groups

Hva skal man velge? Spørsmålet er komplekst og tvetydig, her er et eksempel på endringer i prosjekter på github for 2018-2019:

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

IaC-testrammeverk

Spørsmålet oppstår: hvordan sette alt sammen og lansere det? Kan ta det og gjør det selv hvis det er tilstrekkelig antall ingeniører. Eller du kan ta ferdige løsninger, selv om det ikke er veldig mange av dem:

CFM
Tool

Ansible
Molecule

Chef
Test kjøkken

terra
Terratest

Eksempel på endringer i prosjekter på github for 2018-2019:

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Molekyl vs. Testkjøkken

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

I utgangspunktet vi prøvd å bruke testkitchen:

  1. Lag en VM parallelt.
  2. Bruk Ansible roller.
  3. Kjør inspeksjon.

For 25-35 roller fungerte det 40-70 minutter, noe som var lenge.

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Neste steg var overgangen til jenkins/docker/ansible/molekyl. Idiologisk er alt det samme

  1. Lint-lekebøker.
  2. Still opp rollene.
  3. Start container
  4. Bruk Ansible roller.
  5. Kjør testinfra.
  6. Sjekk idempotens.

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Linting for 40 roller og tester for et dusin begynte å ta omtrent 15 minutter.

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Hva du skal velge avhenger av mange faktorer, som stabelen som brukes, ekspertisen i teamet osv. her bestemmer alle selv hvordan de skal lukke spørsmålet om enhetstesting

IaC-testing: Integrasjonstester

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Det neste trinnet i infrastrukturtestpyramiden vil være integrasjonstester. De ligner på enhetstester:

  1. Infrastrukturen er delt inn i små klosser, for eksempel Ansible roller.
  2. En eller annen form for miljø er distribuert, enten det er docker eller en VM.
  3. For dette testmiljøet gjelder Sett med Ansible roller.
  4. Vi sjekker at alt fungerte som forventet (vi kjører tester).
  5. Vi bestemmer ok eller ikke ok.

Grovt sett sjekker vi ikke ytelsen til et enkelt element i systemet som i enhetstester, vi sjekker hvordan serveren er konfigurert som helhet.

IaC-testing: ende-til-ende-tester

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

På toppen av pyramiden blir vi møtt av End to End-tester. De. Vi sjekker ikke ytelsen til en separat server, et separat skript eller en separat kloss av infrastrukturen vår. Vi sjekker at mange servere er koblet sammen, infrastrukturen vår fungerer slik vi forventer. Dessverre har jeg aldri sett ferdige boksløsninger, sannsynligvis fordi... Infrastrukturen er ofte unik og vanskelig å male og lage et rammeverk for testing. Som et resultat lager alle sine egne løsninger. Det er etterspørsel, men det finnes ikke noe svar. Derfor vil jeg fortelle deg hva som er for å presse andre til å lyde tanker eller gni på nesen min i det faktum at alt ble oppfunnet for lenge siden før oss.

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Et prosjekt med en rik historie. Den brukes i store organisasjoner og sannsynligvis har hver enkelt av dere indirekte krysset veier med den. Applikasjonen støtter mange databaser, integrasjoner, etc. Å vite hvordan infrastrukturen kan se ut er mange docker-compose-filer, og å vite hvilke tester som skal kjøres i hvilket miljø er Jenkins.

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Denne ordningen fungerte ganske lenge, helt til innenfor rammen forskning vi har ikke prøvd å overføre dette til Openshift. Beholderne forblir de samme, men lanseringsmiljøet har endret seg (hei DRY igjen).

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Forskningsideen gikk videre, og i openshift fant de noe som APB (Ansible Playbook Bundle), som lar deg pakke kunnskap om hvordan du distribuerer infrastruktur i en container. De. det er et repeterbart, testbart kunnskapspunkt om hvordan infrastrukturen skal distribueres.

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Alt dette hørtes bra ut helt til vi møtte en heterogen infrastruktur: vi trengte Windows for tester. Som et resultat er kunnskapen om hva, hvor, hvordan de skal distribueres og testes i jenkins.

konklusjonen

Hva jeg lærte av å teste 200 000 linjer med infrastrukturkode

Infrastruktur som kode er

  • Kode i depotet.
  • Menneskelig samhandling.
  • Infrastrukturtesting.

lenker

Kilde: www.habr.com

Legg til en kommentar