ProHoster > Log > administrasjon > Prøver nye verktøy for å bygge og automatisere distribusjon i Kubernetes
Prøver nye verktøy for å bygge og automatisere distribusjon i Kubernetes
Hallo! Nylig har mange kule automatiseringsverktøy blitt utgitt både for å bygge Docker-bilder og for distribusjon til Kubernetes. I denne forbindelse bestemte jeg meg for å leke med GitLab, studere mulighetene grundig og, selvfølgelig, sette opp pipelinen.
Dette arbeidet er inspirert av nettstedet kubernetes.io, som er generert fra kildekoder automatisk, og for hver gruppeforespørsel som sendes, genererer roboten automatisk en forhåndsvisningsversjon av nettstedet med endringene dine og gir en lenke for visning.
Jeg prøvde å bygge en lignende prosess fra bunnen av, men helt bygd på Gitlab CI og gratisverktøy som jeg er vant til å bruke for å distribuere applikasjoner til Kubernetes. I dag skal jeg endelig fortelle deg mer om dem.
Artikkelen vil diskutere verktøy som: Hugo, qbec, kaniko, git-krypt и GitLab CI med å skape dynamiske miljøer.
Som et eksempel på prosjektet vårt vil vi prøve å lage en dokumentasjonspubliseringsside bygget på Hugo. Hugo er en statisk innholdsgenerator.
For de som ikke er kjent med statiske generatorer, vil jeg fortelle deg litt mer om dem. I motsetning til konvensjonelle nettstedsmotorer med en database og noe PHP, som, når en bruker ber om det, genererer sider i farten, er statiske generatorer utformet litt annerledes. De lar deg ta kilder, vanligvis et sett med filer i Markdown-markerings- og temamaler, og deretter kompilere dem til et helt ferdig nettsted.
Det vil si at som et resultat vil du motta en katalogstruktur og et sett med genererte HTML-filer, som du ganske enkelt kan laste opp til en hvilken som helst billig hosting og få et fungerende nettsted.
Du kan installere Hugo lokalt og prøve det ut:
Initialisere et nytt nettsted:
hugo new site docs.example.org
Og samtidig git-depotet:
cd docs.example.org
git init
Så langt er nettstedet vårt uberørt, og for at noe skal vises på det, må vi først koble til et tema; et tema er bare et sett med maler og spesifiserte regler som nettstedet vårt genereres etter.
Til temaet vi skal bruke Lær, som etter min mening er perfekt egnet for en dokumentasjonsside.
Jeg vil være spesielt oppmerksom på at vi ikke trenger å lagre temafilene i prosjektlageret vårt; i stedet kan vi ganske enkelt koble det til ved å bruke git undermodul:
Dermed vil vårt depot bare inneholde filer som er direkte relatert til prosjektet vårt, og det tilknyttede temaet vil forbli som en lenke til et spesifikt depot og en forpliktelse i det, det vil si at det alltid kan hentes fra den opprinnelige kilden og ikke være redd for uforenlige endringer.
La oss korrigere konfigurasjonen config.toml:
baseURL = "http://docs.example.org/"
languageCode = "en-us"
title = "My Docs Site"
theme = "learn"
Allerede på dette stadiet kan du kjøre:
hugo server
Og på adressen http://localhost:1313/ sjekk vår nyopprettede nettside, alle endringer som er gjort i katalogen oppdaterer automatisk den åpne siden i nettleseren, veldig praktisk!
La oss prøve å lage en forside i content/_index.md:
# My docs site
## Welcome to the docs!
You will be very smart :-)
Skjermbilde av den nyopprettede siden
For å generere et nettsted, bare kjør:
hugo
Kataloginnhold offentlig/ og vil være din nettside.
Ja, forresten, la oss umiddelbart legge det til .gitignore:
echo /public > .gitignore
Ikke glem å forplikte endringene våre:
git add .
git commit -m "New site created"
2. Klargjør Dockerfilen
Det er på tide å definere strukturen til depotet vårt. Jeg bruker vanligvis noe sånt som:
dockerfiles/ — inneholder kataloger med Dockerfiler og alt nødvendig for å bygge våre Docker-bilder.
utplassere/ — inneholder kataloger for distribusjon av applikasjonene våre til Kubernetes
Dermed vil vi lage vår første Dockerfile langs stien dockerfiles/website/Dockerfile
FROM alpine:3.11 as builder
ARG HUGO_VERSION=0.62.0
RUN wget -O- https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_linux-64bit.tar.gz | tar -xz -C /usr/local/bin
ADD . /src
RUN hugo -s /src
FROM alpine:3.11
RUN apk add --no-cache darkhttpd
COPY --from=builder /src/public /var/www
ENTRYPOINT [ "/usr/bin/darkhttpd" ]
CMD [ "/var/www" ]
Som du kan se, inneholder Dockerfilen to FRA, kalles denne funksjonen flertrinnsbygging og lar deg ekskludere alt unødvendig fra det endelige docker-bildet.
Dermed vil det endelige bildet bare inneholde mørkhttpd (lett HTTP-server) og offentlig/ — innholdet på vår statisk genererte nettside.
Ikke glem å forplikte endringene våre:
git add dockerfiles/website
git commit -m "Add Dockerfile for website"
3. Bli kjent med kaniko
Som en docker-bildebygger bestemte jeg meg for å bruke kaniko, siden operasjonen ikke krever en docker-demon, og selve byggingen kan utføres på hvilken som helst maskin og cachen kan lagres direkte i registeret, og dermed eliminere behovet for å ha en fullverdig vedvarende lagring.
For å bygge bildet, bare kjør beholderen med kaniko eksekutør og gi den gjeldende byggekontekst; dette kan også gjøres lokalt, via docker:
hvor registry.gitlab.com/kvaps/docs.example.org/website - navnet på docker-bildet ditt; etter bygging vil det automatisk bli lansert i docker-registeret.
Parameter --cache lar deg bufre lag i docker-registeret; for eksempelet som er gitt, vil de bli lagret i registry.gitlab.com/kvaps/docs.example.org/website/cache, men du kan spesifisere en annen bane ved å bruke parameteren --cache-repo.
Skjermbilde av docker-register
4. Bli kjent med qbec
Qbec er et distribusjonsverktøy som lar deg beskrive applikasjonsmanifestene dine deklarativt og distribuere dem til Kubernetes. Ved å bruke Jsonnet som hovedsyntaks kan du i stor grad forenkle beskrivelsen av forskjeller på tvers av flere miljøer, og eliminerer også nesten fullstendig kodegjentakelse.
Dette kan spesielt gjelde i tilfeller der du trenger å distribuere en applikasjon til flere klynger med forskjellige parametere og ønsker å beskrive dem deklarativt i Git.
Qbec lar deg også gjengi Helm-diagrammer ved å gi dem de nødvendige parameterne og deretter betjene dem på samme måte som vanlige manifester, inkludert at du kan bruke forskjellige mutasjoner på dem, og dette lar deg i sin tur bli kvitt behovet for å bruk ChartMuseum. Det vil si at du kan lagre og gjengi diagrammer direkte fra git, der de hører hjemme.
Som jeg sa tidligere, vil vi lagre alle distribusjoner i en katalog utplassere/:
Her er vi først og fremst interessert i spes.miljøer, qbec har allerede opprettet et standardmiljø for oss og tok serveradressen, samt navneområdet fra vår nåværende kubeconfig.
Nå når du distribuerer til standard~~POS=TRUNC miljø, vil qbec alltid bare distribuere til den spesifiserte Kubernetes-klyngen og til det angitte navneområdet, det vil si at du ikke lenger trenger å bytte mellom kontekster og navneområder for å utføre en distribusjon.
Om nødvendig kan du alltid oppdatere innstillingene i denne filen.
Alle miljøene dine er beskrevet i qbec.yaml, og i filen params.libsonnet, hvor det står hvor du kan hente parametrene for dem.
Deretter ser vi to kataloger:
komponenter / - alle manifester for applikasjonen vår vil bli lagret her; de kan beskrives både i jsonnet og vanlige yaml-filer
miljøer/ — her vil vi beskrive alle variablene (parametrene) for våre miljøer.
Som standard har vi to filer:
environments/base.libsonnet - den vil inneholde felles parametere for alle miljøer
environments/default.libsonnet — inneholder parametere som er overstyrt for miljøet standard~~POS=TRUNC
la oss åpne environments/base.libsonnet og legg til parametere for vår første komponent der:
I denne filen beskrev vi tre Kubernetes-enheter samtidig, disse er: Utplassering, Service и Ingress. Hvis vi ville, kunne vi sette dem inn i forskjellige komponenter, men på dette stadiet vil en være nok for oss.
syntaks jsonnet er veldig lik vanlig json, i prinsippet er vanlig json allerede gyldig jsonnet, så i begynnelsen kan det være lettere for deg å bruke nettjenester som yaml2json for å konvertere din vanlige yaml til json, eller, hvis komponentene dine ikke inneholder noen variabler, kan de beskrives i form av vanlig yaml.
Når du jobber med jsonnet Jeg anbefaler på det sterkeste å installere en plugin for redaktøren din
For eksempel er det en plugin for vim vim-jsonnet, som slår på syntaksutheving og kjøres automatisk jsonnet fmt hver gang du lagrer (krever at jsonnet er installert).
Alt er klart, nå kan vi begynne å distribuere:
For å se hva vi har, la oss kjøre:
qbec show default
Ved utgangen vil du se gjengitte yaml-manifester som vil bli brukt på standardklyngen.
Flott, søk nå:
qbec apply default
Ved utgangen vil du alltid se hva som vil bli gjort i klyngen din, qbec vil be deg om å godta endringene ved å skrive y du vil kunne bekrefte intensjonene dine.
Vår applikasjon er klar og distribuert!
Hvis du gjør endringer, kan du alltid gjøre:
qbec diff default
for å se hvordan disse endringene vil påvirke den nåværende distribusjonen
Ikke glem å forplikte endringene våre:
cd ../..
git add deploy/website
git commit -m "Add deploy for website"
5. Prøver Gitlab-runner med Kubernetes-executor
Inntil nylig brukte jeg bare vanlig gitlab-runner på en forhåndspreparert maskin (LXC container) med shell eller docker-executor. I utgangspunktet hadde vi flere slike løpere globalt definert i gitlaben vår. De samlet inn docker-bilder for alle prosjekter.
Men som praksis har vist, er ikke dette alternativet det mest ideelle, både når det gjelder praktisk og sikkerhet. Det er mye bedre og ideologisk mer riktig å ha separate løpere utplassert for hvert prosjekt, eller til og med for hvert miljø.
Heldigvis er ikke dette et problem i det hele tatt, siden vi nå vil distribuere gitlab-runner direkte som en del av vårt prosjekt rett i Kubernetes.
Gitlab gir et ferdig rordiagram for å distribuere gitlab-runner til Kubernetes. Så alt du trenger å gjøre er å finne ut registreringstoken for vårt prosjekt i Innstillinger -> CI / CD -> Løpere og gi den til roret:
yga8y-jdCusVDn_t4Wxc — registreringstoken for prosjektet ditt.
rbac.create=true — gir løperen den nødvendige mengden privilegier for å kunne lage pods for å utføre oppgavene våre ved å bruke kubernetes-executor.
Hvis alt er gjort riktig, skal du se en registrert løper i seksjonen Løpere, i prosjektinnstillingene dine.
Skjermbilde av den lagte løperen
Er det så enkelt? – Ja, så enkelt er det! Ikke mer problemer med å registrere løpere manuelt, fra nå av vil løpere opprettes og ødelegges automatisk.
6. Distribuer Helm-diagrammer med QBEC
Siden vi bestemte oss for å vurdere gitlab-runner en del av prosjektet vårt, er det på tide å beskrive det i Git-depotet vårt.
Vi kan beskrive det som en egen komponent nettsted, men i fremtiden planlegger vi å distribuere forskjellige kopier nettsted veldig ofte, i motsetning til gitlab-runner, som bare vil bli distribuert én gang per Kubernetes-klynge. Så la oss initialisere en egen applikasjon for det:
cd deploy
qbec init gitlab-runner
cd gitlab-runner
Denne gangen vil vi ikke beskrive Kubernetes-entiteter manuelt, men vil ta et ferdig Helm-diagram. En av fordelene med qbec er muligheten til å gjengi Helm-diagrammer direkte fra et Git-depot.
Men å lagre hemmeligheter i Git er vel ikke trygt? Så vi må kryptere dem riktig.
Vanligvis, for én variabels skyld, gir dette ikke alltid mening. Du kan overføre hemmeligheter til qbec og gjennom miljøvariablene til CI-systemet ditt.
Men det er verdt å merke seg at det også er mer komplekse prosjekter som kan inneholde mange flere hemmeligheter; å overføre dem alle gjennom miljøvariabler vil være ekstremt vanskelig.
Dessuten, i dette tilfellet ville jeg ikke kunne fortelle deg om et så fantastisk verktøy som git-krypt.
git-krypt Det er også praktisk ved at det lar deg lagre hele historien til hemmeligheter, samt sammenligne, slå sammen og løse konflikter på samme måte som vi er vant til å gjøre når det gjelder Git.
Det første etter installasjonen git-krypt vi må generere nøkler for vårt depot:
git crypt init
Hvis du har en PGP-nøkkel, kan du umiddelbart legge til deg selv som samarbeidspartner for dette prosjektet:
På denne måten kan du alltid dekryptere dette depotet ved å bruke din private nøkkel.
Hvis du ikke har en PGP-nøkkel og ikke forventer det, kan du gå den andre veien og eksportere prosjektnøkkelen:
git crypt export-key /path/to/keyfile
Dermed alle som har en eksportert nøkkelfil vil kunne dekryptere depotet ditt.
Det er på tide å sette opp vår første hemmelighet.
La meg minne deg på at vi fortsatt er i katalogen deploy/gitlab-runner/, hvor vi har en katalog hemmeligheter/, la oss kryptere alle filene i den, for dette vil vi lage en fil hemmeligheter/.gitattributes med følgende innhold:
Som det fremgår av innholdet, er alle filer maskert * vil bli kjørt gjennom git-krypt, bortsett fra de fleste .gitattributes
Vi kan sjekke dette ved å kjøre:
git crypt status -e
Utdataene vil være en liste over alle filene i depotet som kryptering er aktivert for
Det er alt, nå kan vi trygt gjennomføre endringene våre:
cd ../..
git add .
git commit -m "Add deploy for gitlab-runner"
For å blokkere et depot, bare kjør:
git crypt lock
og umiddelbart vil alle krypterte filer bli til binære noe, det vil være umulig å lese dem.
For å dekryptere depotet, kjør:
git crypt unlock
8. Lag et verktøykassebilde
Et verktøykassebilde er et bilde med alle verktøyene vi skal bruke for å distribuere prosjektet vårt. Den vil bli brukt av Gitlab-løperen til å utføre typiske distribusjonsoppgaver.
Alt er enkelt her, la oss lage en ny dockerfiles/toolbox/Dockerfile med følgende innhold:
FROM alpine:3.11
RUN apk add --no-cache git git-crypt
RUN QBEC_VER=0.10.3
&& wget -O- https://github.com/splunk/qbec/releases/download/v${QBEC_VER}/qbec-linux-amd64.tar.gz
| tar -C /tmp -xzf -
&& mv /tmp/qbec /tmp/jsonnet-qbec /usr/local/bin/
RUN KUBECTL_VER=1.17.0
&& wget -O /usr/local/bin/kubectl
https://storage.googleapis.com/kubernetes-release/release/v${KUBECTL_VER}/bin/linux/amd64/kubectl
&& chmod +x /usr/local/bin/kubectl
RUN HELM_VER=3.0.2
&& wget -O- https://get.helm.sh/helm-v${HELM_VER}-linux-amd64.tar.gz
| tar -C /tmp -zxf -
&& mv /tmp/linux-amd64/helm /usr/local/bin/helm
Som du kan se, i dette bildet installerer vi alle verktøyene vi brukte til å distribuere applikasjonen vår. Vi trenger det ikke her med mindre kubectl, men du vil kanskje leke med det under oppsettfasen av rørledningen.
For å kunne kommunisere med Kubernetes og distribuere til den, må vi også konfigurere en rolle for podene generert av gitlab-runner.
For å gjøre dette, la oss gå til katalogen med gitlab-runner:
cd deploy/gitlab-runner
og legg til en ny komponent komponenter/rbac.jsonnet:
Jeg tror vi trygt kan kalle dette en versjon v0.0.1 og legg til taggen:
git tag v0.0.1
Vi vil legge til tagger når vi trenger å gi ut en ny versjon. Tagger i Docker-bilder vil bli knyttet til Git-tagger. Hvert trykk med en ny tag vil initialisere oppbyggingen av bilder med denne taggen.
La oss gjøre det git push --tags, og la oss se på vår første pipeline:
Skjermbilde av den første rørledningen
Det er verdt å trekke oppmerksomheten din til det faktum at montering av tagger er egnet for å bygge docker-bilder, men er ikke egnet for å distribuere en applikasjon til Kubernetes. Siden nye tagger kan tilordnes til gamle forpliktelser, vil initialisering av pipelinen for dem i dette tilfellet føre til distribusjon av den gamle versjonen.
For å løse dette problemet er byggingen av docker-bilder vanligvis knyttet til tagger, og distribusjonen av applikasjonen til en filial Master, der versjoner av de innsamlede bildene er hardkodet. Det er her du kan initialisere tilbakerulling med en enkel tilbakestilling Master-grener.
10. Automatisering av distribusjon
For at Gitlab-runner skal dekryptere hemmelighetene våre, må vi eksportere depotnøkkelen og legge den til CI-miljøvariablene våre:
Her har vi aktivert flere nye alternativer for qbec:
--root noen/app — lar deg bestemme katalogen til et bestemt program
--force:k8s-context __incluster__ - dette er en magisk variabel som sier at utrullingen vil skje i samme klynge som gtilab-runner kjører. Dette er nødvendig fordi ellers vil qbec prøve å finne en passende Kubernetes-server i kubeconfig
--vente — tvinger qbec til å vente til ressursene den oppretter går inn i Klar-tilstand og først deretter avslutte med en vellykket utgangskode.
-ja - deaktiverer ganske enkelt det interaktive skallet Er du sikker? når den er utplassert.
Og etter git push vi vil se hvordan applikasjonene våre har blitt distribuert:
Skjermbilde av den andre rørledningen
11. Artefakter og montering når du trykker for å mestre
Vanligvis er trinnene beskrevet ovenfor tilstrekkelige til å bygge og levere nesten alle mikrotjenester, men vi ønsker ikke å legge til en tag hver gang vi trenger å oppdatere nettstedet. Derfor vil vi ta en mer dynamisk rute og sette opp en sammendragsdistribusjon i mastergrenen.
Ideen er enkel: nå bildet av vår nettsted vil bli gjenoppbygd hver gang du trykker inn Master, og distribuer deretter automatisk til Kubernetes.
La oss oppdatere disse to jobbene i vår .gitlab-ci.yml:
Vær oppmerksom på at vi har lagt til en tråd Master к refs for jobber build_website og vi bruker nå $CI_COMMIT_REF_NAME i stedet for $CI_COMMIT_TAG, det vil si at vi er løst fra tagger i Git, og nå vil vi skyve et bilde med navnet på commit-grenen som initialiserte pipelinen. Det er verdt å merke seg at dette også vil fungere med tagger, som lar oss lagre øyeblikksbilder av et nettsted med en bestemt versjon i docker-registeret.
Når navnet på docker-taggen for en ny versjon av nettstedet kan være uendret, må vi fortsatt beskrive endringene i Kubernetes, ellers vil den ganske enkelt ikke omdistribuere applikasjonen fra det nye bildet, siden den ikke vil merke noen endringer i distribusjonsmanifest.
alternativ —vm:ext-str digest="$DIGEST" for qbec - lar deg sende en ekstern variabel til jsonnet. Vi vil at den skal omdistribueres i klyngen med hver utgivelse av applikasjonen vår. Vi kan ikke lenger bruke tagnavnet, som nå kan være uforanderlig, siden vi må være knyttet til en spesifikk versjon av bildet og utløse distribusjonen når den endres.
Her vil vi bli hjulpet av Kanikos evne til å lagre et sammendragsbilde til en fil (alternativ --digest-fil)
Deretter vil vi overføre denne filen og lese den på tidspunktet for distribusjon.
La oss oppdatere parametrene for vår deploy/website/environments/base.libsonnet som nå vil se slik ut:
Ferdig, nå forplikter du deg Master initialiserer byggingen av docker-bildet for nettsted, og distribuer den deretter til Kubernetes.
Ikke glem å forplikte endringene våre:
git add .
git commit -m "Configure dynamic build"
Vi sjekker senere git push vi burde se noe slikt:
Skjermbilde av rørledningen for master
I prinsippet trenger vi ikke å omdistribuere gitlab-runner med hvert trykk, med mindre selvfølgelig ingenting har endret seg i konfigurasjonen, la oss fikse det i .gitlab-ci.yml:
Det er på tide å diversifisere rørledningen vår med dynamiske miljøer.
Først, la oss oppdatere jobben build_website i vår .gitlab-ci.yml, fjerner blokken fra den bare, som vil tvinge Gitlab til å utløse den på enhver commit til enhver filial:
De vil bli lansert ved push til alle grener unntatt master og vil distribuere forhåndsvisningsversjonen av nettstedet.
Vi ser et nytt alternativ for qbec: --app-tag — den lar deg merke distribuerte versjoner av applikasjonen og arbeide bare innenfor denne taggen; når du oppretter og ødelegger ressurser i Kubernetes, vil qbec kun operere med dem.
På denne måten kan vi ikke lage et eget miljø for hver anmeldelse, men ganske enkelt gjenbruke det samme.
Her bruker vi også qbec bruke vurdering, i stedet for qbec bruke standard - dette er akkurat det øyeblikket vi vil prøve å beskrive forskjellene for våre miljøer (gjennomgang og standard):
La oss legge til anmeldelse miljø i deploy/website/qbec.yaml
Da vil vi deklarere det deploy/website/params.libsonnet:
local env = std.extVar('qbec.io/env');
local paramsMap = {
_: import './environments/base.libsonnet',
default: import './environments/default.libsonnet',
review: import './environments/review.libsonnet',
};
if std.objectHas(paramsMap, env) then paramsMap[env] else error 'environment ' + env + ' not defined in ' + std.thisFile
Og skriv ned de egendefinerte parameterne for den deploy/website/environments/review.libsonnet:
// this file has the param overrides for the default environment
local base = import './base.libsonnet';
local slug = std.extVar('qbec.io/tag');
local subdomain = std.extVar('subdomain');
base {
components+: {
website+: {
name: 'example-docs-' + slug,
domain: subdomain + '.docs.example.org',
},
},
}
La oss også se nærmere på jobu stop_review, vil den utløses når filialen slettes og for at gitlab ikke skal prøve å sjekke ut blir den brukt GIT_STRATEGY: ingen, senere kloner vi Master- gren og slett anmeldelse gjennom den.
Det er litt forvirrende, men jeg har ikke funnet en vakrere måte ennå.
Et alternativt alternativ ville være å distribuere hver anmeldelse til et hotellnavnområde, som alltid kan rives helt.
Alt fungerer? - flott, slett testgrenen vår: git checkout master, git push origin :test, sjekker vi at miljøslettejobbene fungerte uten feil.
Her vil jeg umiddelbart presisere at enhver utvikler i et prosjekt kan lage grener, han kan også endre .gitlab-ci.yml fil og få tilgang til hemmelige variabler.
Derfor anbefales det sterkt å tillate bruk kun for beskyttede grener, for eksempel i Master, eller lag et eget sett med variabler for hvert miljø.
13. Gjennomgå apper
Gjennomgå apper Dette er en GitLab-funksjon som lar deg legge til en knapp for hver fil i depotet for raskt å vise den i et distribuert miljø.
For at disse knappene skal vises, må du opprette en fil .gitlab/rute-kart.yml og beskriv alle banetransformasjoner i den; i vårt tilfelle vil det være veldig enkelt: