
Përshëndetje! Kohët e fundit kanë dalë shumë mjete fantastike për automatizimin si për ndërtimin e imazheve Docker ashtu edhe për shpërndarjen në Kubernetes. Për këtë arsye, vendosa të luaj me GitLab-in, të shqyrtoj mundësitë e tij dhe, sigurisht, të konfiguroj pipeline-in.
Inspirimi për këtë punë ishte faqja , e cila gjenerohet nga automatizisht, dhe për çdo kërkesë të dërguar për bashkimin, roboti automatikisht gjeneron një version preview të faqes me ndryshimet tuaja dhe ofron një lidhje për ta parë atë.
U përpoqa të ndërtoj një proces të ngjashëm nga fillimi, por tërësisht të ndjehet në GitLab CI dhe me mjete falas që kam mësuar të përdor për shpërndarjen e aplikacioneve në Kubernetes. Sot, përfundimisht do t'ju flas më shumë rreth tyre.
Në këtë artikull do të shqyrtohen mjete si:
Hugo, qbec, kaniko, git-crypt dhe GitLab CI me krijimin e mjediseve dinamike.
Përmbajtja
1. Njoftim me Hugo
Si një shembull i projektit tonë, do të provojmë të krijojmë një faqe për publikimin e dokumentacionit, e cila është ndërtuar në Hugo. Hugo është një gjenerues statik për përmbajtjen.
Për ata që nuk janë të njohur me gjeneruesit statik, do t'ju tregoj pak më shumë rreth tyre. Në ndryshim nga motorët e zakonshëm të faqeve me një bazë të dhënash dhe ndonjë PHP, të cilat, në kërkesën e përdoruesit, krijojnë faqet në flakë, gjeneruesit statik funksionojnë nd slightly tjetër. Ata lejojnë të merrni kodin burimor, zakonisht një grup skedarësh në formatin Markdown dhe shabllone teme, dhe më pas t'i kompiloni ato në një faqe të plotë të gatshme.
Kjo do të thotë se në daljen do të merrni një strukturë dosjesh dhe një grup skedarësh html të gjeneruar, të cilët mund të ngarkoni thjesht në çdo host të lirë dhe të merrni një faqe funksionale.
Hugo mund të instalohet lokalisht dhe të provoni atë në veprim:
Inicioni një faqe të re:
hugo new site docs.example.orgDhe për njëherë, një repozitor git:
cd docs.example.org
git initDerisa faqja jonë është e pastër, duhet të lidhemi me një temë; tema është thjesht një grup template-esh dhe rregullash të përcaktuara përmes të cilave gjenerohet faqja jonë.
Si temë do të përdorim , e cila, në mendimin tim, është mëse e përshtatshme për një faqe me dokumentacion.
Dua të theksoj se nuk na nevojitet të ruajmë skedarët e temës në depot e projektit tonë; përkundrazi, mund ta lidhim thjesht duke përdorur git submodule:
git submodule add https://github.com/matcornic/hugo-theme-learn themes/learnKështu, në depot tonë do të ndodhen vetëm skedarët që i përkasin gjithashtu projektit tonë, ndërsa tema e lidhur do të mbetet si një lidhje në një depo të caktuar dhe commit në të, që do të thotë se gjithmonë mund ta nxjerrim nga burimi origjinal dhe të mos shqetësohemi për ndryshimet e pamundura.
Le t'i bëjmë disa modifikime konfigurimit config.toml:
baseURL = "http://docs.example.org/"
languageCode = "en-us"
title = "Faqja ime e Dokumentacionit"
theme = "learn"Që tani, mund ta fillojmë:
hugo serverDhe në adresën të kontrollojmë faqen tonë të sapo krijuar; të gjitha ndryshimet të bëra në direktorinë automatike përditësojnë gjithashtu faqen e hapur në shfletues, shumë e përshtatshme!
Le të provojmë të krijojmë një faqe titulluese në content/_index.md:
# My docs site
## Welcome to the docs!
You will be very smart :-)Kopja ekranit të faqes së sapo krijuar

Për të gjeneruar faqen mjafton të filloni:
hugoPërmbajtja e direktorisë public/ do të jetë faqja juaj.
Po, për t'u siguruar, le të shtojmë shpesh në .gitignore:
echo /public > .gitignoreMos harro të commitosh ndryshimet tona:
git add .
git commit -m "Faqja e re u krijua"2. Përgatitja e Dockerfile
Ka ardhur koha të përcaktojmë strukturën e depot tonë. Zakonisht unë përdor diçka si:
.
├── deploy
│ ├── app1
│ └── app2
└── dockerfiles
├── image1
└── image2- dockerfiles/ kjo përmban drejtime që kanë Dockerfile dhe gjithçka të nevojshme për ndërtimin e imazhëve tanë docker.
- deploy/ ka direktori për të implementuar aplikacionet tona në Kubernetes.
Kështu, ne do ta krijojmë Dockerfile tonë të parë në 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" ]Siç mund ta vini re, Dockerfile përmban dy FROM, kjo mundësi quhet dhe lejon të përjashtosh nga imazhi përfundimtar docker çdo gjë të kote.
Në këtë mënyrë, imazhi përfundimtar do të përmbajë vetëm darkhttpd (një server HTTP i lehtë) dhe public/ — përmbajtjen e uebsit tonë të gjeneruar statikisht.
Mos harro të commitosh ndryshimet tona:
git add dockerfiles/website
git commit -m "Shto Dockerfile për uebsajtin"3. Njoftimi me kaniko
Si ndërtues të imazheve docker, vendosa të përdor , pasi për funksionimin e tij nuk kërkohet prania e daemonit docker, dhe ndërtimin mund ta bësh në çdo makinë duke ruajtur cache direkt në registry, duke eliminuar kështu nevojën për të pasur një ruajtje të përhershme.
Për ndërtimin e imazhit, mjafton të startosh një kontejner me kaniko executor dhe t'i kalosh atij kontekstin aktual të ndërtimit, mund ta bësh këtë edhe lokal, përmes 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.1Ku registry.gitlab.com/kvaps/docs.example.org/website — emri i imazhit tuaj docker, pasi të ndërtohet, ai do të shtohet automatikisht në docker registry.
Parametri —cache lejon ruajtjen e shtresave në docker registry, për shembullin e dhënë, ato do të ruajnë në registry.gitlab.com/kvaps/docs.example.org/website/cache, por mund të specifikoni një rrugë tjetër duke përdorur parametrin —cache-repo.
Screenshot docker-registry

4. Njoftimi me qbec
— është një mjet deploy-i që lejon përshkrimin deklarativ të manifekteve të aplikacionit tuaj dhe vendosjen e tyre në Kubernetes. Përdorimi i Jsonnet si sintaksë kryesore lejon të thjeshtosh shumë përshkrimin e ndryshimeve për disa mjedise, dhe gjithashtu eliminon pothuajse plotësisht përsëritjen e kodit.
Kjo mund të jetë veçanërisht relevante kur ju nevojitet të vendosni një aplikacion në disa klasterë me parametra të ndryshëm dhe dëshironi t'i përshkruani ato në mënyrë deklarative në Git.
Qbec gjithashtu lejon të renditni Helm charts duke iu kaluar atyre parametrat e nevojshëm dhe më pas t'i përdorni ato ashtu si manifestet e zakonshme, përfshirë mundësinë për t'i bërë ndryshime të ndryshme, e cila, nga ana tjetër, lejon të eliminohet nevoja për të përdorur ChartMuseum. Pra, është e mundur të ruani dhe renditni charts direkt nga git, ku ato kanë vendin e tyre.
Siç thashë më parë, të gjitha zbatimet do t'i ruajmë në direktorinë deploy/:
mkdir deploy
cd deployLe të inizializojmë aplikacionin tonë të parë:
qbec init website
cd websiteTani struktura e aplikacionit tonë duket kështu:
└── komponentet
├── mjediset
│ ├── base.libsonnet
│ └── default.libsonnet
├── params.libsonnet
└── qbec.yamlle të shohim skedarin qbec.yaml:
apiVersion: qbec.io/v1alpha1
kind: App
metadata:
name: website
spec:
environments:
default:
defaultNamespace: docs
server: https://kubernetes.example.org:8443
vars: {}Këtu na intereson kryesisht spec.environments, qbec ka krijuar për ne ambientin default dhe ka marrë adresën e serverit, si dhe namespace nga kubeconfig-i ynë aktual.
Tani gjatë deploy-it në default ambient, qbec gjithmonë do të deploy-ojë vetëm në cluster-in Kubernetes të caktuar dhe në namespace të caktuar, kështu që nuk do të keni më nevojë të kaloni mes konteksteve dhe namespace-ve për të kryer deploy-in.
Në rast nevoje, mund të përditësoni gjithmonë cilësimet në këtë skedar.
Të gjitha ambientet tuaja përshkruhen në qbec.yaml, dhe në skedarin params.libsonnet, ku thuhet se nga duhet të merrni parametrat për to.
Më pas ne shohim dy drejtime:
- komponentet/ — këtu do të ruhen të gjitha manifestet për aplikacionin tonë, ato mund të përshkruheshin si në jsonnet ashtu edhe në skedarë të zakonshëm yaml
- mjediset/ — këtu do të përshkruajmë të gjitha variablat (parametrat) për ambientet tona.
Në mënyrë të parazgjedhur ne kemi dy skedarë:
- mjediset/base.libsonnet — do të ketë parametrat e përbashkët për të gjitha ambientet
- mjediset/default.libsonnet — përmban parametrat e anuluar për ambientin default
Le të hapim mjediset/base.libsonnet dhe të shtojmë parametrat për komponentin tonë të parë:
{
komponentet: {
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',
},
},
}Të krijojmë gjithashtu komponentin tonë të parë komponentet/website.jsonnet:
ambienti lokal = {
emri: std.extVar('qbec.io/env'),
namespace: std.extVar('qbec.io/defaultNs'),
};
ambienti p = import '.. /params.libsonnet';
ambienti params = p.components.website;
[
{
versioniApi: 'apps/v1',
lloji: 'Deployment',
metadata: {
etiketat: { app: params.name },
emri: params.name,
},
specifika: {
replikat: params.replicas,
selektori: {
matchLabels: {
app: params.name,
},
},
shablloni: {
metadata: {
etiketat: { app: params.name },
},
specifika: {
kontejnerët: [
{
emri: 'darkhttpd',
imazhi: params.image,
portet: [
{
containerPort: params.containerPort,
},
],
},
],
nodeSelector: params.nodeSelector,
tolerimet: params.tolerations,
imagePullSecrets: [{ emri: 'regsecret' }],
},
},
},
},
{
versioniApi: 'v1',
lloji: 'Service',
metadata: {
etiketat: { app: params.name },
emri: params.name,
},
specifika: {
selektori: {
app: params.name,
},
portet: [
{
port: params.servicePort,
targetPort: params.containerPort,
},
],
},
},
{
versioniApi: 'extensions/v1beta1',
lloji: 'Ingress',
metadata: {
annotations: {
'kubernetes.io/ingress.class': params.ingressClass,
},
etiketat: { app: params.name },
emri: params.name,
},
specifika: {
rregullat: [
{
host: params.domain,
http: {
rrugët: [
{
pasqyra: {
emriShërbimit: params.name,
portiShërbimit: params.servicePort,
},
},
],
},
},
],
},
},
]Në këtë skedë ne kemi përshkruar tri entitete Kubernetes, këto: Zhvillimi, Shërbimi dhe Ingress. Po të dëshironim, mund të ndanim ato në komponente të ndryshme, por në këtë fazë një i tillë është i mjaftueshëm.
Sintaksa jsonnet është shumë e ngjashme me json të zakonshëm, pasi që json i zakonshëm tashmë është një jsonnet i vlefshëm, prandaj në fillim mund të jetë më e lehtë të shfrytëzoni shërbime online si yaml2json për të konvertuar yaml-in e njohur të zakonshëm në json, ose, nëse komponentet tuaja nuk përmbajnë variabla, ato mund të përshkruhen si një yaml i zakonshëm.
Kur punoni me jsonnet është me rëndësi të instaloni një plugin për redaktorin tuaj.
Për shembull, për vim ekziston një plugin vim-jsonnet, i cili përfshin theksimin e sintaksës dhe e ekzekuton automatikisht jsonnet fmt me çdo ruajtje (kërkon që jsonnet të jetë i instaluar).
Tani jemi gati, mund të fillojmë me deployment-in:
Për të parë se çfarë kemi arritur, do të ekzekutojmë:
qbec show defaultNë daljen e saj do të shihni manifestet yaml që do të aplikohen në klasterin default.
Shkëlqyer, tani do ta aplikojmë:
qbec apply defaultNë dalje gjithmonë do të shihni se çfarë do të bëhet në klasterin tuaj, qbec do t'ju kërkojë të jepni pajtim për ndryshimet duke shkruar y do të mund të konfirmoni qëllimet tuaja.
Tani, aplikacioni ynë është përfunduar dhe është vendosur!
Në rast se bëni ndonjë ndryshim, gjithmonë mund të ekzekutoni:
qbec diff defaultpër të parë si do të reflektohen këto ndryshime në implementimin aktual
Mos harro të commitosh ndryshimet tona:
cd ..\/..
git add deploy\/website
git commit -m "Shto implementim për uebin"5. Provojmë Gitlab-runner me Kubernetes-executor
Derisa nuk ka kaluar shumë kohë, unë kam përdorur vetëm gitlab-runner në një makinë të përgatitur më parë (në një kontejner LXC) me shell- ose docker-executor. Fillimisht kishim disa nga këta runner globalisht të përcaktuar në Gitlab-in tonë. Ata krijonin imazhe docker për të gjitha projektet.
Por siç tregoi praktika — ky opsion nuk është më i miri, as në aspektin e praktikës, as në atë të sigurisë. Më mirë dhe ideologjikisht është më e drejtë të kemi rinj të veçantë të vendosur për çdo projekt, madje për çdo mjedis.
Fatmirësisht, kjo nuk është aspak një problem, sepse tani do të implementojmë gitlab-runner direkt si pjesë e projektit tonë përmes Kubernetes.
Gitlab ofron një helm-chart të gatshëm për implementimin e gitlab-runner në Kubernetes. Kështu që çdo gjë që ju nevojitet, është të zbuloni registration token për projektin tonë në Settings —> CI \/ CD —> Runners dhe t'ia kaloni helm:
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-runnerKu:
- — adresa e serverit tuaj Gitlab.
- yga8y-jdCusVDn_t4Wxc — registration token për projektin tuaj.
- rbac.create=true — i jep rinjve sasinë e nevojshme të privilegjeve për t'u mundësuar krijimin e pods për të ekzekutuar detyrat tona me kubernetes-executor.
Nëse gjithçka është bërë siç duhet, duhet të shihni një rinj të regjistruar në seksionin Runners, në cilësimet e projektit tuaj.
Screenshot i rinjve të shtuar

A është kaq e lehtë? — po, kaq e lehtë! Asnjë më shumë mundim me regjistrimin e rinjve me dorë, nga ky moment rinjtë do të krijohen dhe shkatërrohen automatikisht.
6. Implementimi i Helm-chart-eve me QBEC
Pasi kemi vendosur të konsiderojmë gitlab-runner si pjesë të projektit tonë, është koha ta përshkruajmë atë në repositalin tonë Git.
Mund të kishim përshkruar atë si një komponent të veçantë website, por më vonë planifikojmë të implementojmë kopje të ndryshme website shumë shpesh, në krahasim me gitlab-runner, i cili do të implementohet vetëm një herë për çdo Kubernetes-cluster. Pra, le të inicializojmë një aplikacion të veçantë për të:
cd deploy
qbec init gitlab-runner
cd gitlab-runnerTë thishtë herë nuk do të përshkruajmë entitetet e Kubernetes manualisht, por do të marrim një helm chart të gatshëm. Një nga përfitimet e qbec është mundësia për të renderuar helm chart-e direkt nga depoja Git.
Le të lidhemi me të duke përdorur git submodule:
git submodule add https://gitlab.com/gitlab-org/charts/gitlab-runner vendor/gitlab-runnerTani direktoriumi vendor/gitlab-runner ka në ne një depo me chart për gitlab-runner.
Në mënyrë të ngjashme, mund të lidhen edhe depo të tjera, për shembull e tërë depon me chart të zyrtarëve.
Le të përshkruajmë komponentin components/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,
}
)Argumenti i parë për expandHelmTemplate ne i japim rrugën për chart-in, pastaj params.values, të cilat do t'i marrim nga parametrat e mjedisit, më pas vjen një objekt me
- nameTemplate — emri i lëshimit
- namespace — namespaces që i kalohen helm-it
- thisFile — parametër i domosdoshëm, që përcjell rrugën për skedarin aktual
- verbose — tregon komandën helm template me të gjitha argumentet gjatë renderimit të chart-it
Tani do të përshkruajmë parametrat për komponentin tonë në mjediset/base.libsonnet:
local secrets = import '../secrets/base.libsonnet';
{
components: {
gitlabRunner: {
name: 'gitlab-runner',
values: {
gitlabUrl: 'https://gitlab.com/',
rbac: {
create: true,
},
runnerRegistrationToken: secrets.runnerRegistrationToken,
},
},
},
}Vini re runnerRegistrationToken ne e marrim nga një skedar të jashtëm secrets/base.libsonnet, le të krijojmë atë:
{
runnerRegistrationToken: 'yga8y-jdCusVDn_t4Wxc',
}Le të kontrollojmë nëse gjithçka funksionon:
qbec show defaultnëse gjithçka është në rregull, atëherë mund të fshijmë lëshimin tonë të mëparshëm, të ndihmuar përmes Helm:
helm uninstall gitlab-runnerdhe ta ndihmojmë atë sërish, por tashmë përmes qbec:
qbec apply default7. Njohja me git-crypt
është një mjet që lejon konfigurimin e enkriptimit transparent për depozitat tuaja.
Aktualisht, struktura e direktoriumit tonë për gitlab-runner duket ashtu:
.
├── components
│ ├── gitlab-runner.jsonnet
├── environments
│ ├── base.libsonnet
│ └── default.libsonnet
├── params.libsonnet
├── qbec.yaml
├── secrets
│ └── base.libsonnet
└── vendor
└── gitlab-runner (submodule)Por të ruash sekretet në Git nuk është e sigurt, a nuk është kështu? Kështu që duhet t'i enkriptojmë ato siç duhet.
Në përgjithësi, për një variabël të vetme, kjo nuk ka gjithmonë kuptim. Mund të kaloni sekretet në qbec dhe përmes variablave të mjedisit të sistemit tuaj CI.
Por të vërehet, ka edhe projekte më të komplikuara, të cilat mund të përmbajnë shumë më tepër sekrete, duke i kaluar ata të gjithë përmes variableve të mjedisit do të ishte jashtëzakonisht e vështirë.Për më tepër, në këtë rast nuk do të mund të flisja me ju për një mjet të tillë të mrekullueshëm si git-crypt.
git-crypt është edhe i përshtatshëm për atë që ruan gjithë historinë e sekreteve, si dhe lejon të krahasoni, bashkoni dhe zgjidhni konflikte ashtu siç jemi mësuar ta bëjmë me Git.
E para pas instalimit git-crypt na nevojitet të gjenerojmë çelësat për depozitën tonë:
git crypt initNëse keni një çelës PGP, atëherë mund të shtoni menjëherë veten si bashkëpunëtor për këtë projekt:
git-crypt add-gpg-user kvapss@gmail.comKështu do të jeni gjithmonë në gjendje të dekriptoni këtë depozitë duke përdorur çelësin tuaj privat.
Por nëse nuk keni çelës PGP dhe nuk parashikohet, atëherë mund të shkoni një rrugë tjetër dhe eksportoni çelësin e projektit:
git crypt export-key /path/to/keyfileKështu, kushdo që ka çelësin e eksportuar keyfile do të jetë në gjendje të dekriptojë depozitën tuaj.
Ka ardhur koha për të konfiguruar sekretin tonë të parë.
Të kujtojmë, ende jemi në drejtorinë deploy/gitlab-runner/, ku kemi një drejtorinë secrets/, le të enkriptojmë të gjitha skedaret në të, për këtë le të krijojmë skedarin secrets/.gitattributes me këtë përmbajtje:
* filter=git-crypt diff=git-crypt
.gitattributes !filter !diffSiç duket nga përmbajtja, të gjitha skedaret sipas modelit * do të kalojnë përmes git-crypt, përveç vetë .gitattributes
Këtë mund ta verifikojmë duke ekzekutuar:
git crypt status -eNë daljen do të marrim një listë të të gjitha skedareve në depozitë të cilat kanë aktivizuar enkriptimin.
Kjo është gjithçka, tani mund të angazhojmë me besim ndryshimet tona:
cd ../..
git add .
git commit -m "Shto deploy për gitlab-runner"Për të bllokuar depozitën mjafton të ekzekutoni:
git crypt lockdhe menjëherë të gjitha skedaret e enkriptuara do të shndërrohen në diçka binare, do të jetë e pamundur t'i lexoni ato.
Për të dekriptuar depozitën, ekzekutoni:
git crypt unlock8. Krijojmë imazhin e toolbox-it
Imazhi i toolbox-it — është një imazh me të gjitha mjetet që do të përdorim për trajtimin e projektit tonë. Ai do të përdoret nga gitlab-runner për të kryer detyrat standarde të trajtimit.
Këtu është e thjeshtë, krijoni një të ri dockerfiles/toolbox/Dockerfile me këtë përmbajtje:
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/helmSi mund të vini re, në këtë imazh instalojmë të gjitha utilitarët që kemi përdorur për të bërë deploy të aplikacionit tonë. Këtu nuk na nevojitet vetëm kubectl, por ndoshta do të dëshironit të luanit me të gjatë konfigurimit të pipeline.
Gjithashtu, për të pasur mundësinë të komunikoni me Kubernetes dhe të bëni deploy në të, na nevojitet të konfigurojmë një rol për pod-ët e gjeneruar nga gitlab-runner.
Për këtë, do të kalojmë në direktorinë me gitlab-runner-in:
cd deploy/gitlab-runnerdhe do të shtojmë komponentin e ri components/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,
},
],
},
]Po ashtu do ta përshkruajmë parametrat e rinj në mjediset/base.libsonnet, i cili tani duket kështu:
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',
},
},
}Vini re $.components.rbac.name i referohet emri për komponentin rbac
Le të kontrollojmë se çfarë ka ndryshuar:
qbec diff defaultdhe të aplikojmë ndryshimet tona në Kubernetes:
qbec apply defaultPo ashtu mos haroni të commitoni ndryshimet tona në git:
cd ../..
git add dockerfiles/toolbox
git commit -m "Shtoni Dockerfile për toolbox"
git add deploy/gitlab-runner
git commit -m "Konfiguroni gitlab-runner për të përdorur toolbox"9. Pipeline-i ynë i parë dhe ndërtimi i imazheve sipas etiketimeve
Në rrënjën e projektit do të krijojmë .gitlab-ci.yml me këtë përmbajtje:
.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:
- tagsKujdes, ne po përdorim GIT_SUBMODULE_STRATEGY: normal për ato punë që kërkojnë qartë inicializimin e nënmodulëve përpara ekzekutimit.
Mos harro të commitosh ndryshimet tona:
git add .gitlab-ci.yml
git commit -m "Automatizo ndërtimin e docker"Mendoj se mund ta quajmë këtë version v0.0.1 dhe të vendosim etiketën:
git tag v0.0.1Etiketat do të vendosen sa herë që do të na nevojitet të lëshojmë një version të ri. Etiketat në imazhet Docker do të lidheshin me etiketat Git. Çdo push me një etiketë të re do të inicializonte ndërtimin e imazheve me këtë etikët.
Të kryejmë git push —tags, dhe të shohim pipeline-in tonë të parë:
Screenshot i pipeline-it të parë

Vlen të theksohet se ndërtimi përmes etiketave është i përshtatshëm për ndërtimin e imazheve docker, por nuk është i përshtatshëm për implementimin e aplikacioneve në Kubernetes. Duke pasur parasysh se etiketat e reja mund të caktohen edhe për komitet e vjeter, në këtë rast inicializimi i pipeline-it për to do të çonte në implementimin e versionit të vjetër.
Për të zgjidhur këtë problem, zakonisht ndërtimi i imazheve docker lidhet me etiketat, ndërsa implementimi i aplikacionit me degën master, në të cilën janë të hardkoduara versionet e imazheve të ndërtuara. Në këtë rast do të jeni në gjendje të inicializoni roll-back me një revert master-dege.
10. Automatizimi i implementimit
Për ta bërë të mundur që Gitlab-runner të dekriptojë sekretet tona, ne do të nevojitet të eksportojmë çelësin e depozitës, dhe ta shtojmë në variablat mjedisore të CI tonë:
git crypt export-key /tmp/docs-repo.key
base64 -w0 /tmp/docs-repo.key; echostrungën e marrë do ta ruajmë në Gitlab, për këtë do të kalojmë në cilësimet e projektit tonë:
Cilësimet —> CI / CD —> Variablat
Dhe do të krijojmë një variabël të re:
Tipi
Çelësi
Vlera
I mbrojtur
I maskuar
Shkalla
Skedari
GITCRYPT_KEY
<your string>
true (në kohën e trajnimit mund edhe false)
true
Të gjitha mjediset
Screenshot i variablës së shtuar

Tani do ta përditësojmë .gitlab-ci.yml duke shtuar në të:
.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 --yesKëtu kemi përfshirë disa opsione të reja për qbec:
- —root some/app — lejon të përcaktojë direktorinë e aplikacionit të veçantë
- —force:k8s-context __incluster__ — kjo është një variabël magjike që thotë se deploy do të ndodhë në të njëjtin klaster ku është aktivizuar gitlab-runner. Kjo është e nevojshme, sepse ndryshe qbec do të përpiqet të gjejë një server Kubernetes të përshtatshëm në kubeconfig tuaj
- —wait — bën që qbec të presë derisa burimet që krijon të kalojnë në gjendjen ‘Ready’ dhe vetëm atëherë përfundon me një kod exit të suksesshëm.
- —yes — thjesht çaktivizon shell-in interaktiv A jeni të sigurt? në deploy.
Mos harro të commitosh ndryshimet tona:
git add .gitlab-ci.yml
git commit -m "Automatizo aktivitete"Dhe pas git push do të shohim si janë deployuar aplikacionet tona:
Në screenshotin e dytë të pipeline-it

11. Artefaktet dhe ndërtimi kur pushtojmë në master
Në përgjithësi, hapat e përshkruar më sipër janë mjaftueshëm për ndërtimin dhe dorëzimin e pothuajse çdo mikrosherbimi, por ne nuk duam të vendosim një tag sa herë që na nevojitet të azhurojmë faqen. Prandaj do të ndjekim një rrugë më dinamike dhe do të konfigurojmë deploy-n sipas digest në degën master.
Ideja është e thjeshtë: tani imazhi ynë website do të rinovohet çdo herë që bëhet push në master, dhe pas kësaj do të deployohet automatikisht në Kubernetes.
Le të azhurnojmë këto dy punë në .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"Vini re, kemi shtuar degën master në refs për punën build_website dhe tani po përdorim $CI_COMMIT_REF_NAME në vend të $CI_COMMIT_TAG, pra ne po shkëputemi nga tag-et në Git dhe tani do të shtojmë imazhin me emrin e degës së commit-it që aktivizoi pipeline-in. Duhet të theksohet se kjo do të funksionojë gjithashtu me tag-et, duke na lejuar të ruajmë snapshot-e të faqes me një version të përcaktuar në docker-registry.
Kur emri i docker-tagut për versionin e ri të faqes mund të mbetet i pandryshuar, ne ende duhet të përshkruajmë ndryshimet për Kubernetes, përndryshe ai thjesht nuk do ta ri-deploy-apë aplikacionin nga imazhi i ri, pasi nuk do të vërejë asnjë ndryshim në manifestin e deploy-it.
Opcioni —vm:ext-str digest="$DIGEST" për qbec — lejon kalimin e një variabli të jashtëm në jsonnet. Ne duam që me çdo çlirim të aplikacionit tonë, ai të ri-deploy-ohet në klaster. Tani nuk mund ta përdorim emrin e tagut, i cili mund të jetë i pandryshuar, pasi na nevojitet të lidhim me një version specifik të imazhit dhe të aktivizojmë deploy-in me ndryshimin e tij.
Këtu na ndihmon mundësia e Kaniko për të ruajtur digest-in e imazhit në një skedë (opcioni —digest-file)
Pastaj këtë skedë ne do ta kalojmë dhe do ta lexojmë në momentin e deploy-it.
Do të përditësojmë parametrat për deploy/website/environments/base.libsonnet i cili tani do të duket kështu:
{
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',
},
},
}Gati, tani çdo commit në master do të inicojë ndërtimin e imazhit docker për website, dhe më pas ri-deploy-in e tij në Kubernetes.
Mos harro të commitosh ndryshimet tona:
git add .
git commit -m "Konfiguroni ndërtimin dinamik"Do të verifikojmë, pas git push duhet të shohim diçka të ngjashme:
Screenshot i pipeline-it për master

I përgjithshëm, ne nuk kemi nevojë të ri-deploy-ojmë gitlab-runner çdo herë që bëhet një push, përveç nëse, sigurisht, nuk pati asnjë ndryshim në konfigurimin e tij, le të korrigjojmë këtë në .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/**/*ndryshimet do të lejojë të monitorojmë ndryshimet në deploy/gitlab-runner/ dhe do të aktivizojë punën tonë vetëm në rast të tillë
Mos harro të commitosh ndryshimet tona:
git add .gitlab-ci.yml
git commit -m "Redukto deploy-n e gitlab-runner"git push, kështu më mirë:
Screenshot i përditësuar i pipeline-it

12. Mjediset dinamike
Ka ardhur koha të pasurojmë pipeline-in tonë me mjedise dinamike.
Fillimisht do të përditësojmë punën build_website në .gitlab-ci.yml, duke e hequr bllokun only, gjë që do ta bëjë Gitlab ta aktivizojë atë me çdo commit në çdo degë:
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/Më pas do të përditësojmë punën deploy_website, do ta shtojmë një bllok mjedis:
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"Kjo do t'i lejojë Gitlab-it të asociojë punimin me prod mjedisin dhe të shfaqë lidhjen e saktë për të.
Tani do të shtojmë edhe dy punime:
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: manualAto do të aktivizohen me push në çdo degë përveç master dhe do të publikojnë versionin preview të faqeve.
Ne shohim një mundësi të re për qbec: —app-tag — ajo lejon të etiketojmë versionet e publikuara të aplikacionit dhe të punojmë vetëm brenda këtij etiketi, gjatë krijimit dhe shkatërrimit të burimeve në Kubernetes qbec do të operojë vetëm me to.
Kështu, ne mund të mos krijojmë një mjedis të veçantë për çdo rishikim, por thjesht të ripërdorim të njëjtin.
Këtu gjithashtu përdorim qbec apply review, në vend të qbec apply default — është pikërisht momenti kur do të përpiqemi të përshkruajmë dallimet për mjediset tona (rishikimi dhe default):
Shtojmë mjedisin në deploy/website/qbec.yaml
spec:
environments:
review:
defaultNamespace: docs
server: https://kubernetes.example.org:8443Pastaj do ta deklarojmë në 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.thisFileDhe do të shkruajmë parametrat personal të tij në 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',
},
},
}Le të shohim më me kujdes punimin stop_review, ajo do të aktivizohet kur të fshihet dega dhe që gitlab të mos përpiqet të bëjë checkout në të, përdoret GIT_STRATEGY: none, më vonë ne e klonojmë master-de ve të heqim review përmes saj.
Një pak e komplikuar, por më shumë mënyra më e bukur nuk kam gjetur akoma.
Një alternativë mund të jetë deploy-i i çdo review në një namespace të veçantë, që gjithmonë mund të fshihet plotësisht.
Mos harro të commitosh ndryshimet tona:
git add .
git commit -m "Aktivizo review automatik"git push, git checkout -b test, git push origin test, kontrollojmë:
Screenshot i ambienteve të krijuara në Gitlab

A po funksionon? — shkëlqyeshëm, heqim degën tonë të testit: git checkout master, git push origin :test, kontrollojmë që punët për heqjen e ambientit të jenë ekzekutuar pa gabime.
Këtu menjëherë është e nevojshme të sqarojmë se krijimi i degëve mund të bëhet nga çdo zhvillues në projekt, ai gjithashtu mund të modifikojë .gitlab-ci.yml skedarin dhe të ketë qasje në variablat sekretë.
Prandaj, rekomandohet që t'u lejohet përdorimi i tyre vetëm për dega të mbrojtura, për shembull në master, ose të krijoni një set të veçantë variablash për çdo ambient.
13. Review Apps
është një mundësi e Gitlab-it, që lejon që për çdo skedar në repositor do të shtohet një buton për shikimin e shpejtë në ambientin e vendosur.
Për të pasur këto butona, duhet krijuar një skedar .gitlab/route-map.yml dhe të përshkruani në të të gjitha transformimet e rrugëve, në rastin tonë do të jetë shumë e lehtë:
# Indices
- source: /content/(.+?)_index.(md|html)/
public: '1'
# Pages
- source: /content/(.+?).(md|html)/
public: '1/'Mos harro të commitosh ndryshimet tona:
git add .gitlab/
git commit -m "Aktivizo review apps"git push, dhe kontrollojmë:
Screenshot i butonit Review App

Job is done!
Burimet e projektit:
- në Gitlab:
- në GitHub:
Faleminderit për vëmendjen, shpresoj se ju ka pëlqyer ![]()
Burimi: habr.com
