
Hej! En masse smarte automatiseringsværktøjer er blevet frigivet på det seneste til både opbygning af Docker-billeder og implementering til Kubernetes. I denne henseende besluttede jeg at lege med Gitlab, hvordan man studerer dets muligheder og selvfølgelig opsætter en pipeline.
Denne side er inspireret af , som er genereret fra automatisk, og for hver sendt pull-anmodning genererer robotten automatisk en forhåndsvisning af webstedet med dine ændringer og giver et link til visning.
Jeg forsøgte at bygge en lignende proces fra bunden, men helt bygget på Gitlab CI og gratis værktøjer, som jeg plejede at bruge til at implementere applikationer til Kubernetes. I dag vil jeg endelig fortælle mere om dem.
Artiklen vil dække værktøjer som:
Hugo, qbec, kaniko, git-krypt и GitLab CI med skabelsen af dynamiske miljøer.
Indhold
1. Lær Hugo at kende
Som et eksempel på vores projekt vil vi forsøge at skabe en dokumentationspubliceringsside bygget på Hugo. Hugo er en statisk indholdsgenerator.
For dem, der ikke er bekendt med statiske generatorer, vil jeg fortælle dig lidt mere om dem. I modsætning til almindelige webstedsmotorer med en database og en slags php, som, når brugeren anmoder om det, genererer sider i farten, er statiske generatorer arrangeret lidt anderledes. De giver dig mulighed for at tage kildekoden, normalt et sæt filer i Markdown-markerings- og temaskabeloner, og derefter kompilere dem til et helt færdigt websted.
Det vil sige, ved udgangen vil du få en mappestruktur og et sæt af genererede html-filer, som du blot kan uploade til en hvilken som helst billig hosting og få et fungerende websted.
Du kan installere Hugo lokalt og prøve det:
Initialisering af det nye websted:
hugo new site docs.example.orgOg samtidig git-depotet:
cd docs.example.org
git initIndtil videre er vores websted uberørt, og for at noget skal vises på det, skal vi først forbinde et tema, et tema er blot et sæt skabeloner og fastlagte regler, som vores websted genereres efter.
Som tema vil vi bruge , som efter min mening er bedst egnet til en side med dokumentation.
Jeg vil gerne være særlig opmærksom på, at vi ikke behøver at gemme temafilerne i vores projekts lager, i stedet kan vi blot forbinde det vha. git undermodul:
git submodule add https://github.com/matcornic/hugo-theme-learn themes/learnSåledes vil kun filer, der er direkte relateret til vores projekt, være i vores repository, og det forbundne tema vil forblive som et link til et specifikt depot og en commit i det, det vil sige, det kan altid trækkes fra den originale kilde og ikke være bange. af uforenelige ændringer.
Lad os rette opsætningen config.toml:
baseURL = "http://docs.example.org/"
languageCode = "en-us"
title = "My Docs Site"
theme = "learn"Allerede på dette stadium kan du køre:
hugo serverOg på adressen tjek vores nyoprettede websted, alle ændringer foretaget i mappen opdaterer automatisk den åbne side i browseren, meget praktisk!
Lad os prøve at oprette en titelside i content/_index.md:
# My docs site
## Welcome to the docs!
You will be very smart :-)Skærmbillede af den nyoprettede side

For at generere et websted skal du blot køre:
hugoKatalogindhold offentlig/ og vil være dit websted.
Ja, forresten, lad os straks bringe det ind .gitignore:
echo /public > .gitignoreGlem ikke at foretage vores ændringer:
git add .
git commit -m "New site created"2. Forberedelse af Dockerfilen
Det er tid til at definere strukturen af vores depot. Normalt bruger jeg noget som:
.
├── deploy
│ ├── app1
│ └── app2
└── dockerfiles
├── image1
└── image2- dockerfiler/ - indeholder mapper med Dockerfiler og alt det nødvendige for at bygge vores docker-billeder.
- indsætte/ - indeholder mapper til implementering af vores applikationer i Kubernetes
Således vil vi oprette vores første Dockerfile undervejs 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, indeholder Dockerfilen to FRA, kaldes denne mulighed og giver dig mulighed for at udelukke alt unødvendigt fra det endelige docker-billede.
Det endelige billede vil således kun indeholde mørkhttpd (letvægts HTTP-server) og offentlig/ - indholdet af vores statisk genererede websted.
Glem ikke at foretage vores ændringer:
git add dockerfiles/website
git commit -m "Add Dockerfile for website"3. Lær kaniko at kende
Som opbygger af docker-billeder besluttede jeg at bruge , da det ikke kræver en docker-dæmon for at fungere, og selve samlingen kan udføres på enhver maskine og gemme cachen direkte i registreringsdatabasen, og derved slippe af med behovet for at have et fuldgyldigt vedvarende lager.
For at bygge billedet skal du bare køre beholderen med kaniko eksekutor og videregive den aktuelle byggekontekst til det, du kan gøre det lokalt via docker:
docker run -ti --rm
-v $PWD:/workspace
-v ~/.docker/config.json:/kaniko/.docker/config.json:ro
gcr.io/kaniko-project/executor:v0.15.0
--cache
--dockerfile=dockerfiles/website/Dockerfile
--destination=registry.gitlab.com/kvaps/docs.example.org/website:v0.0.1hvor registry.gitlab.com/kvaps/docs.example.org/website - navnet på dit docker-billede, efter at det er bygget, vil det automatisk blive lanceret i docker-registret.
Parameter --cache giver dig mulighed for at cache lag i docker-registret, for det givne eksempel vil de blive gemt i registry.gitlab.com/kvaps/docs.example.org/website/cache, men du kan angive en anden sti med parameteren --cache-repo.
Skærmbillede af docker-registry

4. Introduktion til qbec
er et implementeringsværktøj, der giver dig mulighed for deklarativt at beskrive dine applikationsmanifester og implementere dem til Kubernetes. Brug af Jsonnet som hovedsyntaks gør det meget nemt at beskrive forskellene for flere miljøer og eliminerer også næsten fuldstændig kodegentagelse.
Dette kan især være tilfældet i tilfælde, hvor du har brug for at implementere en applikation i flere klynger med forskellige parametre og ønsker at beskrive dem deklarativt i Git.
Qbec giver dig også mulighed for at gengive Helm-diagrammer ved at give dem de nødvendige parametre og derefter operere på dem på samme måde som almindelige manifester, inklusive evnen til at anvende forskellige mutationer på dem, og dette eliminerer igen behovet for at bruge ChartMuseum. Det vil sige, at du kan gemme og gengive diagrammer direkte fra git, hvor de hører hjemme.
Som jeg sagde før, vil vi gemme alle implementeringer i mappen indsætte/:
mkdir deploy
cd deployLad os initialisere vores første applikation:
qbec init website
cd websiteNu ser strukturen af vores applikation sådan ud:
.
├── components
├── environments
│ ├── base.libsonnet
│ └── default.libsonnet
├── params.libsonnet
└── qbec.yamlse på filen qbec.yaml:
apiVersion: qbec.io/v1alpha1
kind: App
metadata:
name: website
spec:
environments:
default:
defaultNamespace: docs
server: https://kubernetes.example.org:8443
vars: {}Her er vi primært interesserede i spec.miljøer, qbec har allerede oprettet standardmiljøet for os og tog serveradressen og navneområdet fra vores nuværende kubeconfig.
Nu når de udrulles til standard miljø, vil qbec altid kun implementere til den angivne Kubernetes-klynge og til det angivne navneområde, dvs. du behøver ikke længere at skifte mellem kontekster og navnerum for at implementere.
Om nødvendigt kan du altid opdatere indstillingerne i denne fil.
Alle dine miljøer er beskrevet i qbec.yaml, og i filen params.libsonnet, som siger, hvor du skal tage parametrene for dem.
Dernæst ser vi to mapper:
- komponenter / - alle manifester til vores applikation vil blive gemt her, de kan beskrives både i jsonnet og i almindelige yaml-filer
- miljøer/ - her vil vi beskrive alle variabler (parametre) for vores miljøer.
Som standard har vi to filer:
- environments/base.libsonnet - den vil indeholde fælles parametre for alle miljøer
- environments/default.libsonnet - indeholder parametre omdefineret for miljøet standard
lad os åbne environments/base.libsonnet og tilføje parametre for vores første komponent der:
{
components: {
website: {
name: 'example-docs',
image: 'registry.gitlab.com/kvaps/docs.example.org/website:v0.0.1',
replicas: 1,
containerPort: 80,
servicePort: 80,
nodeSelector: {},
tolerations: [],
ingressClass: 'nginx',
domain: 'docs.example.org',
},
},
}Lad os også skabe vores første komponent komponenter/website.jsonnet:
local env = {
name: std.extVar('qbec.io/env'),
namespace: std.extVar('qbec.io/defaultNs'),
};
local p = import '../params.libsonnet';
local params = p.components.website;
[
{
apiVersion: 'apps/v1',
kind: 'Deployment',
metadata: {
labels: { app: params.name },
name: params.name,
},
spec: {
replicas: params.replicas,
selector: {
matchLabels: {
app: params.name,
},
},
template: {
metadata: {
labels: { app: params.name },
},
spec: {
containers: [
{
name: 'darkhttpd',
image: params.image,
ports: [
{
containerPort: params.containerPort,
},
],
},
],
nodeSelector: params.nodeSelector,
tolerations: params.tolerations,
imagePullSecrets: [{ name: 'regsecret' }],
},
},
},
},
{
apiVersion: 'v1',
kind: 'Service',
metadata: {
labels: { app: params.name },
name: params.name,
},
spec: {
selector: {
app: params.name,
},
ports: [
{
port: params.servicePort,
targetPort: params.containerPort,
},
],
},
},
{
apiVersion: 'extensions/v1beta1',
kind: 'Ingress',
metadata: {
annotations: {
'kubernetes.io/ingress.class': params.ingressClass,
},
labels: { app: params.name },
name: params.name,
},
spec: {
rules: [
{
host: params.domain,
http: {
paths: [
{
backend: {
serviceName: params.name,
servicePort: params.servicePort,
},
},
],
},
},
],
},
},
]I denne fil beskrev vi tre Kubernetes-enheder på én gang, disse er: Deployment, Service и Ingress. Hvis det ønskes, kunne vi flytte dem ind i forskellige komponenter, men på dette tidspunkt er én nok for os.
syntaks jsonnet meget lig almindelig json, i princippet er almindelig json allerede et gyldigt jsonnet, så i starten kan det være lettere for dig at bruge onlinetjenester som f.eks. yaml2json at konvertere din sædvanlige yaml til json, eller hvis dine komponenter ikke indeholder nogen variable, så kan de beskrives i form af almindelig yaml.
Når man arbejder med jsonnet Jeg anbefaler dig kraftigt at installere et plugin til din editor
For eksempel er der et plugin til vim vim-jsonnet, som aktiverer syntaksfremhævning og udføres automatisk jsonnet fmt ved hver lagring (kræver, at jsonnet er installeret).
Alt er klar, nu kan vi starte implementeringen:
For at se, hvad vi har, lad os køre:
qbec show defaultVed udgangen vil du se de gengivede yaml-manifester, der vil blive anvendt på standardklyngen.
Godt, ansøg nu:
qbec apply defaultPå outputtet vil du altid se, hvad der vil blive gjort i din klynge, qbec vil bede dig om at acceptere ændringerne ved at skrive y du kan bekræfte dine hensigter.
Færdig nu er vores app implementeret!
Hvis der foretages ændringer, kan du altid køre:
qbec diff defaultfor at se, hvordan disse ændringer vil påvirke den aktuelle implementering
Glem ikke at foretage vores ændringer:
cd ../..
git add deploy/website
git commit -m "Add deploy for website"5. Prøv Gitlab-runner med Kubernetes-executor
Indtil for nylig har jeg kun brugt almindelig gitlab-runner på en præpareret maskine (LXC container) med shell- eller docker-executor. I starten havde vi flere af disse løbere defineret globalt i vores gitlab. De byggede docker-billeder til alle projekter.
Men som praksis har vist, er denne mulighed ikke den mest ideelle, både med hensyn til praktisk og med hensyn til sikkerhed. Det er meget bedre og ideologisk korrekt at have separate løbere indsat for hvert projekt, og endda for hvert miljø.
Heldigvis er dette slet ikke et problem, da vi nu vil implementere gitlab-runner direkte som en del af vores projekt lige i Kubernetes.
Gitlab leverer et færdigt rordiagram til implementering af gitlab-runner til Kubernetes. Så alt hvad du behøver at vide er registreringstoken til vores projekt i Indstillinger -> CI / CD -> Løbere og send det til roret:
helm repo add gitlab https://charts.gitlab.io
helm install gitlab-runner
--set gitlabUrl=https://gitlab.com
--set runnerRegistrationToken=yga8y-jdCusVDn_t4Wxc
--set rbac.create=true
gitlab/gitlab-runnerHvor:
- er adressen på din Gitlab-server.
- yga8y-jdCusVDn_t4Wxc - registreringstoken til dit projekt.
- rbac.create=sand - giver løberen det nødvendige antal privilegier for at kunne oprette pods til at udføre vores opgaver ved hjælp af kubernetes-executor.
Hvis alt er udført korrekt, bør du se den tilmeldte løber i afsnittet Løbere, i dine projektindstillinger.
Skærmbillede af den tilføjede løber

Er det så simpelt? – ja, så enkelt er det! Ikke mere besvær med manuelt at registrere løbere, fra nu af vil løbere blive oprettet og destrueret automatisk.
6. Implementer Helm-diagrammer med QBEC
Da vi har besluttet at overveje gitlab-runner en del af vores projekt, er det tid til at beskrive det i vores Git-lager.
Vi kunne beskrive det som en separat komponent hjemmeside, men i fremtiden planlægger vi at implementere forskellige kopier hjemmeside meget ofte, i modsætning til gitlab-runner, som kun vil blive implementeret én gang pr. Kubernetes-klynge. Så lad os initialisere en separat applikation til det:
cd deploy
qbec init gitlab-runner
cd gitlab-runnerDenne gang vil vi ikke beskrive Kubernetes-enheder manuelt, men tage et færdigt Helm-diagram. En af fordelene ved qbec er evnen til at gengive Helm-diagrammer direkte fra et Git-lager.
Lad os aktivere det ved hjælp af git undermodul:
git submodule add https://gitlab.com/gitlab-org/charts/gitlab-runner vendor/gitlab-runnerNu mappen leverandør/gitlab-runner indeholder vores repository med et diagram for gitlab-runner.
Andre depoter kan forbindes på lignende måde, for eksempel hele depotet med officielle diagrammer
Lad os beskrive komponenten komponenter/gitlab-runner.jsonnet:
local env = {
name: std.extVar('qbec.io/env'),
namespace: std.extVar('qbec.io/defaultNs'),
};
local p = import '../params.libsonnet';
local params = p.components.gitlabRunner;
std.native('expandHelmTemplate')(
'../vendor/gitlab-runner',
params.values,
{
nameTemplate: params.name,
namespace: env.namespace,
thisFile: std.thisFile,
verbose: true,
}
)Det første argument til expandHelmTemplate så passerer vi stien til kortet params.værdier, som vi tager fra miljøparametrene, så kommer objektet med
- navnSkabelon - udgivelsesnavn
- navnerum — navneområde overført til roret
- denne fil - en påkrævet parameter, der sender stien til den aktuelle fil
- ordrig - viser kommando styreskabelon med alle argumenter ved gengivelse af et diagram
Lad os nu beskrive parametrene for vores komponent i environments/base.libsonnet:
local secrets = import '../secrets/base.libsonnet';
{
components: {
gitlabRunner: {
name: 'gitlab-runner',
values: {
gitlabUrl: 'https://gitlab.com/',
rbac: {
create: true,
},
runnerRegistrationToken: secrets.runnerRegistrationToken,
},
},
},
}Bemærk venligst runnerRegistrationToken vi henter fra ekstern fil secrets/base.libsonnet, lad os skabe det:
{
runnerRegistrationToken: 'yga8y-jdCusVDn_t4Wxc',
}Lad os tjekke om alt virker:
qbec show defaulthvis alt er i orden, så kan vi fjerne vores tidligere installerede via Helm-udgivelse:
helm uninstall gitlab-runnerog implementer det, men gennem qbec:
qbec apply default7. Introduktion til git-crypt
er et værktøj, der giver dig mulighed for at opsætte gennemsigtig kryptering til dit lager.
I øjeblikket ser vores mappestruktur for gitlab-runner sådan ud:
.
├── components
│ ├── gitlab-runner.jsonnet
├── environments
│ ├── base.libsonnet
│ └── default.libsonnet
├── params.libsonnet
├── qbec.yaml
├── secrets
│ └── base.libsonnet
└── vendor
└── gitlab-runner (submodule)Men at gemme hemmeligheder i Git er ikke sikkert, er det? Så vi skal kryptere dem ordentligt.
Normalt af hensyn til én variabel giver det ikke altid mening. Du kan overføre hemmeligheder til qbec og gennem miljøvariablerne i dit CI-system.
Men det er værd at bemærke, at der også er mere komplekse projekter, der kan indeholde meget flere hemmeligheder, det vil være ekstremt svært at føre dem alle gennem miljøvariabler.Derudover ville jeg i dette tilfælde ikke være i stand til at fortælle dig om et så vidunderligt værktøj som git-krypt.
git-krypt Det er også praktisk, fordi det giver dig mulighed for at gemme hele historien om hemmeligheder, samt sammenligne, flette og løse konflikter på samme måde, som vi plejede at gøre det i tilfældet med Git.
Det første efter installationen git-krypt vi skal generere nøgler til vores lager:
git crypt initHvis du har en PGP-nøgle, kan du straks tilføje dig selv som samarbejdspartner for dette projekt:
git-crypt add-gpg-user kvapss@gmail.comPå denne måde kan du altid dekryptere dette lager ved hjælp af din private nøgle.
Hvis du ikke har en PGP-nøgle og ikke forventes at have, så kan du gå den anden vej og eksportere projektnøglen:
git crypt export-key /path/to/keyfileSåledes kan enhver, der besidder en eksporteret nøglefil vil være i stand til at dekryptere dit lager.
Det er tid til at oprette vores første hemmelighed.
Lad mig minde dig om, at vi stadig er i mappen deploy/gitlab-runner/hvor vi har en mappe hemmeligheder/, lad os kryptere alle filerne i den, for dette vil vi oprette en fil hemmeligheder/.gitattributes med indhold som dette:
* filter=git-crypt diff=git-crypt
.gitattributes !filter !diffSom det kan ses af indholdet, er alle filer efter maske * vil løbe igennem git-krypt, med undtagelse af .gitattributes
Vi kan tjekke dette ved at køre:
git crypt status -eVed udgangen får vi en liste over alle filer i depotet, for hvilke kryptering er aktiveret
Det er det, nu kan vi trygt foretage vores ændringer:
cd ../..
git add .
git commit -m "Add deploy for gitlab-runner"For at blokere depotet er det nok at udføre:
git crypt lockog straks vil alle krypterede filer blive til et binært noget, det vil være umuligt at læse dem.
For at dekryptere depotet skal du køre:
git crypt unlock8. Opret et værktøjskassebillede
Et værktøjskassebillede er et billede med alle de værktøjer, vi vil bruge til at implementere vores projekt. Det vil blive brugt af gitlab runner til at udføre typiske implementeringsopgaver.
Alt er enkelt her, vi skaber en ny dockerfiler/værktøjskasse/Dockerfil med indhold som dette:
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/helmSom du kan se, installerer vi i dette billede alle de værktøjer, vi brugte til at implementere vores applikation. Vi har ikke brug for her, medmindre kubectl, men du vil måske lege med det, når du opsætter pipelinen.
For at kunne kommunikere med Kubernetes og implementere til det, er vi også nødt til at konfigurere en rolle for pods genereret af gitlab-runner.
For at gøre dette skal du gå til mappen med gitlab-runner'om:
cd deploy/gitlab-runnerog tilføje en ny komponent komponenter/rbac.jsonnet:
local env = {
name: std.extVar('qbec.io/env'),
namespace: std.extVar('qbec.io/defaultNs'),
};
local p = import '../params.libsonnet';
local params = p.components.rbac;
[
{
apiVersion: 'v1',
kind: 'ServiceAccount',
metadata: {
labels: {
app: params.name,
},
name: params.name,
},
},
{
apiVersion: 'rbac.authorization.k8s.io/v1',
kind: 'Role',
metadata: {
labels: {
app: params.name,
},
name: params.name,
},
rules: [
{
apiGroups: [
'*',
],
resources: [
'*',
],
verbs: [
'*',
],
},
],
},
{
apiVersion: 'rbac.authorization.k8s.io/v1',
kind: 'RoleBinding',
metadata: {
labels: {
app: params.name,
},
name: params.name,
},
roleRef: {
apiGroup: 'rbac.authorization.k8s.io',
kind: 'Role',
name: params.name,
},
subjects: [
{
kind: 'ServiceAccount',
name: params.name,
namespace: env.namespace,
},
],
},
]Vi beskriver også de nye parametre i environments/base.libsonnet, som nu ser sådan ud:
local secrets = import '../secrets/base.libsonnet';
{
components: {
gitlabRunner: {
name: 'gitlab-runner',
values: {
gitlabUrl: 'https://gitlab.com/',
rbac: {
create: true,
},
runnerRegistrationToken: secrets.runnerRegistrationToken,
runners: {
serviceAccountName: $.components.rbac.name,
image: 'registry.gitlab.com/kvaps/docs.example.org/toolbox:v0.0.1',
},
},
},
rbac: {
name: 'gitlab-runner-deploy',
},
},
}Bemærk venligst $.components.rbac.name hentyder til navn for komponent RBAC
Lad os tjekke, hvad der er ændret:
qbec diff defaultog anvende vores ændringer på Kubernetes:
qbec apply defaultGlem heller ikke at forpligte vores ændringer til git:
cd ../..
git add dockerfiles/toolbox
git commit -m "Add Dockerfile for toolbox"
git add deploy/gitlab-runner
git commit -m "Configure gitlab-runner to use toolbox"9. Vores første pipeline og samling af billeder efter tags
I roden af projektet vil vi skabe .gitlab-ci.yml med indhold som dette:
.build_docker_image:
stage: build
image:
name: gcr.io/kaniko-project/executor:debug-v0.15.0
entrypoint: [""]
before_script:
- echo "{"auths":{"$CI_REGISTRY":{"username":"$CI_REGISTRY_USER","password":"$CI_REGISTRY_PASSWORD"}}}" > /kaniko/.docker/config.json
build_toolbox:
extends: .build_docker_image
script:
- /kaniko/executor --cache --context $CI_PROJECT_DIR/dockerfiles/toolbox --dockerfile $CI_PROJECT_DIR/dockerfiles/toolbox/Dockerfile --destination $CI_REGISTRY_IMAGE/toolbox:$CI_COMMIT_TAG
only:
refs:
- tags
build_website:
extends: .build_docker_image
variables:
GIT_SUBMODULE_STRATEGY: normal
script:
- /kaniko/executor --cache --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/dockerfiles/website/Dockerfile --destination $CI_REGISTRY_IMAGE/website:$CI_COMMIT_TAG
only:
refs:
- tagsBemærk venligst, at vi bruger GIT_SUBMODULE_STRATEGY: normal til de job, hvor du eksplicit skal initialisere undermoduler før udførelse.
Glem ikke at foretage vores ændringer:
git add .gitlab-ci.yml
git commit -m "Automate docker build"Jeg tror, man roligt kan kalde det en version v0.0.1 og tilføj et tag:
git tag v0.0.1Vi vil hænge tags, når vi skal udgive en ny version. Tags i Docker-billeder vil blive knyttet til Git-tags. Hvert tryk med et nyt tag vil initialisere en billedopbygning med det tag.
Lad os gøre det git push --tags, og se på vores første pipeline:
Skærmbillede af den første pipeline

Det er værd at påpege, at tag-baserede builds er gode til at bygge docker-billeder, men ikke til at implementere en applikation til Kubernetes. Da nye tags også kan tildeles til gamle commits, vil initialisering af pipelinen for dem i dette tilfælde føre til implementeringen af den gamle version.
For at løse dette problem er opbygningen af docker-billeder normalt knyttet til tags og implementeringen af applikationen til filialen Master, hvor versionerne af de indsamlede billeder er hardkodet. Det er i dette tilfælde, at du kan initialisere rollback med en simpel tilbagevending Master-grene.
10. Implementer automatisering
For at Gitlab-runner kan dekryptere vores hemmeligheder, skal vi eksportere lagernøglen og tilføje den til vores CI-miljøvariabler:
git crypt export-key /tmp/docs-repo.key
base64 -w0 /tmp/docs-repo.key; echovi gemmer den resulterende streng i Gitlab, for dette vil vi gå til indstillingerne for vores projekt:
Indstillinger —> CI / CD —> Variabler
Og opret en ny variabel:
Type
Nøgle
Værdi
Beskyttet
maskeret
Anvendelsesområde
File
GITCRYPT_KEY
<your string>
true (på træningstidspunktet kan du false)
true
All environments
Skærmbillede af den tilføjede variabel

Lad os nu opdatere vores .gitlab-ci.yml tilføjer det:
.deploy_qbec_app:
stage: deploy
only:
refs:
- master
deploy_gitlab_runner:
extends: .deploy_qbec_app
variables:
GIT_SUBMODULE_STRATEGY: normal
before_script:
- base64 -d "$GITCRYPT_KEY" | git-crypt unlock -
script:
- qbec apply default --root deploy/gitlab-runner --force:k8s-context __incluster__ --wait --yes
deploy_website:
extends: .deploy_qbec_app
script:
- qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yesHer har vi aktiveret nogle nye muligheder for qbec:
- --root nogle/app - giver dig mulighed for at definere biblioteket for en specifik applikation
- --force:k8s-context __incluster__ - dette er en magisk variabel, der siger, at implementeringen vil ske i den samme klynge, som gtilab-runner kører i. Dette er nødvendigt, ellers vil qbec forsøge at finde en passende Kubernetes-server i din kubeconfig
- -vente - tvinger qbec til at vente, indtil de ressourcer, den skaber, går ind i tilstanden Klar og først derefter fuldføre med en vellykket exit-kode.
- -Ja - deaktiverer bare den interaktive shell Er du sikker? under udsendelsen.
Glem ikke at foretage vores ændringer:
git add .gitlab-ci.yml
git commit -m "Automate deploy"Og efter git push vi vil se, hvordan vores applikationer blev implementeret:
Skærmbillede af den anden pipeline

11. Artefakter og samling ved skubbe til master
Normalt er ovenstående trin nok til at bygge og levere næsten enhver mikroservice, men vi ønsker ikke at tilføje et tag, hver gang vi skal opdatere webstedet. Derfor vil vi gå på en mere dynamisk måde og opsætte en digest-implementering i mastergrenen.
Ideen er enkel: nu billedet af vores hjemmeside vil blive genopbygget hver gang du trykker på Master, og implementer derefter automatisk til Kubernetes.
Lad os opdatere disse to jobs i vores .gitlab-ci.yml:
build_website:
extends: .build_docker_image
variables:
GIT_SUBMODULE_STRATEGY: normal
script:
- mkdir -p $CI_PROJECT_DIR/artifacts
- /kaniko/executor --cache --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/dockerfiles/website/Dockerfile --destination $CI_REGISTRY_IMAGE/website:$CI_COMMIT_REF_NAME --digest-file $CI_PROJECT_DIR/artifacts/website.digest
artifacts:
paths:
- artifacts/
only:
refs:
- master
- tags
deploy_website:
extends: .deploy_qbec_app
script:
- DIGEST="$(cat artifacts/website.digest)"
- qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST"Bemærk, at vi har tilføjet en filial Master к ref til job build_website og vi bruger nu $CI_COMMIT_REF_NAME i stedet for $CI_COMMIT_TAG, det vil sige, vi slipper af med tags i Git, og nu vil vi skubbe billedet med navnet på den commit-gren, der initialiserede din pipeline. Det er værd at bemærke, at dette også vil fungere med tags, som giver os mulighed for at gemme snapshots af webstedet med en specifik version i docker-registret.
Når navnet på docker-tagget for den nye version af webstedet kan være uændret, er vi stadig nødt til at beskrive ændringerne for Kubernetes, ellers vil den ganske enkelt ikke geninstallere applikationen fra det nye billede, da den ikke vil bemærke nogen ændringer i implementeringsmanifest.
valgmulighed --vm:ext-str digest="$DIGEST" for qbec - giver dig mulighed for at sende en ekstern variabel til jsonnet. Vi ønsker, at vores applikation skal omplaceres i klyngen med hver udgivelse. Vi kan ikke længere bruge navnet på tagget, som nu kan være uændret, da vi skal binde til en specifik version af billedet og udløse implementeringen, når den ændres.
Her vil Kanikos evne til at gemme sammendraget af billedet til en fil hjælpe os (option --digest-fil)
Så overfører vi denne fil og læser den på tidspunktet for implementeringen.
Lad os opdatere parametrene for vores deploy/website/environments/base.libsonnet som nu kommer til at se sådan ud:
{
components: {
website: {
name: 'example-docs',
image: 'registry.gitlab.com/kvaps/docs.example.org/website@' + std.extVar('digest'),
replicas: 1,
containerPort: 80,
servicePort: 80,
nodeSelector: {},
tolerations: [],
ingressClass: 'nginx',
domain: 'docs.example.org',
},
},
}Færdig, nu skal enhver forpligte sig Master initialiserer opbygningen af docker-billedet til hjemmeside, og derefter implementere det til Kubernetes.
Glem ikke at foretage vores ændringer:
git add .
git commit -m "Configure dynamic build"Tjek det ud bagefter git push vi burde se noget som dette:
Pipeline screenshot til master

I princippet behøver vi ikke at ominstallere gitlab-runner med hvert tryk, medmindre selvfølgelig intet er ændret i dens konfiguration, lad os rette dette i .gitlab-ci.yml:
deploy_gitlab_runner:
extends: .deploy_qbec_app
variables:
GIT_SUBMODULE_STRATEGY: normal
before_script:
- base64 -d "$GITCRYPT_KEY" | git-crypt unlock -
script:
- qbec apply default --root deploy/gitlab-runner --force:k8s-context __incluster__ --wait --yes
only:
changes:
- deploy/gitlab-runner/**/*ændringer vil holde styr på ændringer i deploy/gitlab-runner/ og vil kun udløse vores job, hvis der er nogen
Glem ikke at foretage vores ændringer:
git add .gitlab-ci.yml
git commit -m "Reduce gitlab-runner deploy"git push, det er bedre:
Skærmbillede af den opdaterede pipeline

12. Dynamiske miljøer
Det er tid til at diversificere vores pipeline med dynamiske miljøer.
Lad os først opdatere jobbet build_website i vores .gitlab-ci.yml, ved at fjerne blokken fra den kun, hvilket vil tvinge Gitlab til at udløse det på enhver commit til enhver filial:
build_website:
extends: .build_docker_image
variables:
GIT_SUBMODULE_STRATEGY: normal
script:
- mkdir -p $CI_PROJECT_DIR/artifacts
- /kaniko/executor --cache --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/dockerfiles/website/Dockerfile --destination $CI_REGISTRY_IMAGE/website:$CI_COMMIT_REF_NAME --digest-file $CI_PROJECT_DIR/artifacts/website.digest
artifacts:
paths:
- artifacts/Opdater derefter jobbet deploy_website, tilføje en blok der miljø:
deploy_website:
extends: .deploy_qbec_app
environment:
name: prod
url: https://docs.example.org
script:
- DIGEST="$(cat artifacts/website.digest)"
- qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST"Dette vil give Gitlab mulighed for at knytte jobbet til prod miljøet og vise det korrekte link til det.
Lad os nu tilføje to job mere:
deploy_website:
extends: .deploy_qbec_app
environment:
name: prod
url: https://docs.example.org
script:
- DIGEST="$(cat artifacts/website.digest)"
- qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST"
deploy_review:
extends: .deploy_qbec_app
environment:
name: review/$CI_COMMIT_REF_NAME
url: http://$CI_ENVIRONMENT_SLUG.docs.example.org
on_stop: stop_review
script:
- DIGEST="$(cat artifacts/website.digest)"
- qbec apply review --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST" --vm:ext-str subdomain="$CI_ENVIRONMENT_SLUG" --app-tag "$CI_ENVIRONMENT_SLUG"
only:
refs:
- branches
except:
refs:
- master
stop_review:
extends: .deploy_qbec_app
environment:
name: review/$CI_COMMIT_REF_NAME
action: stop
stage: deploy
before_script:
- git clone "$CI_REPOSITORY_URL" master
- cd master
script:
- qbec delete review --root deploy/website --force:k8s-context __incluster__ --yes --vm:ext-str digest="$DIGEST" --vm:ext-str subdomain="$CI_ENVIRONMENT_SLUG" --app-tag "$CI_ENVIRONMENT_SLUG"
variables:
GIT_STRATEGY: none
only:
refs:
- branches
except:
refs:
- master
when: manualDe vil blive udløst ved push til alle grene undtagen master og vil implementere en forhåndsvisningsversion af webstedet.
Vi ser en ny mulighed for qbec: --app-tag - det giver dig mulighed for at tagge installerede versioner af applikationen og kun arbejde inden for dette tag; når du opretter og ødelægger ressourcer i Kubernetes, vil qbec kun fungere på dem.
Vi kan således ikke skabe et separat miljø for hver anmeldelse, men blot genbruge det samme.
Her bruger vi også qbec anvende anmeldelse, i stedet for qbec anvender standard - dette er præcis det øjeblik, hvor vi vil forsøge at beskrive forskellene for vores miljøer (gennemgang og standard):
Lad os tilføje gennemgå miljø i deploy/website/qbec.yaml
spec:
environments:
review:
defaultNamespace: docs
server: https://kubernetes.example.org:8443Så erklærer vi 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.thisFileOg skriv tilpassede parametre for det i 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',
},
},
}Lad os også se nærmere på jobbet stop_anmeldelse, vil den blive udløst, når grenen fjernes, og så gitlab ikke forsøger at betale på den, bruges GIT_STRATEGY: ingen, senere kloner vi Master-forgrene og slette anmeldelse gennem det.
Lidt forvirrende, men jeg har endnu ikke fundet en smukkere måde.
En alternativ mulighed ville være at implementere hver anmeldelse til et hotelnavneområde, som altid kan rives ned i sin helhed.
Glem ikke at foretage vores ændringer:
git add .
git commit -m "Enable automatic review"git push, git checkout -b test, git push oprindelsestest, kontrollere:
Skærmbillede af oprettede miljøer i Gitlab

Fungerer alt? - super, slet vores testgren: git checkout mester, git push oprindelse :test, kontrollerer vi, at jobs til sletning af miljøet fungerede uden fejl.
Her vil jeg straks præcisere, at enhver udvikler i projektet kan oprette grene, han kan også ændre .gitlab-ci.yml fil og få adgang til hemmelige variabler.
Derfor anbefales det kraftigt kun at tillade deres anvendelse til beskyttede grene, for eksempel i Master, eller opret et separat sæt variabler for hvert miljø.
13 Gennemgå apps
dette er en gitlab-funktion, der giver dig mulighed for at tilføje en knap for hver fil i depotet for hurtigt at se den i det installerede miljø.
For at disse knapper skal vises, skal du oprette en fil .gitlab/rute-map.yml og beskriv i det alle transformationerne af stierne, i vores tilfælde vil det være meget enkelt:
# Indices
- source: /content/(.+?)_index.(md|html)/
public: '1'
# Pages
- source: /content/(.+?).(md|html)/
public: '1/'Glem ikke at foretage vores ændringer:
git add .gitlab/
git commit -m "Enable review apps"git push, og tjek:
Skærmbillede af knappen Review App

Job er gjort!
Projektkilder:
- på gitlab:
- på GitHub:
Tak for din opmærksomhed, jeg håber du kunne lide den ![]()
Kilde: www.habr.com
