
Përshëndetje! Kohët e fundit kanë dalë shumë mjete të shkëlqyera për automatizimin e ndërtimit të imazheve Docker dhe për shpërndarjen në Kubernetes. Prandaj, vendosa të eksperimentoja me GitLab-in, të studioja mundësitë e tij, dhe natyrisht, të konfiguroja pipeline-in.
Inspirimi për këtë punë erdhi nga website , i cili krijohet nga automatike, dhe për çdo tërheqje të dërguar, roboti krijon automatikisht një version preview të website-it me ndryshimet tuaja dhe ofron një lidhje për ta parë.
Unë kam përpjekur të ndërtoj një proces të ngjashëm nga e para, por tërësisht të ndërtuar mbi GitLab CI dhe mjete të lira, të cilat kam mësuar t'i përdor për shpërndarjen e aplikacioneve në Kubernetes. Sot, përfundimisht, do t'ju tregoj më shumë për to.
Në këtë artikull do të shqyrtohen mjete të tilla si:
Hugo, qbec, kaniko, git-crypt dhe GitLab CI në 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 ndërtuar mbi Hugo. Hugo është një gjenerues statik për përmbajtjen.
Për ata që nuk janë të njohur me gjeneratorët statik, do të flas pak më shumë rreth tyre. Në dallim nga motorët e zakonshëm të faqeve me bazë të dhënash dhe ndonjë php, të cilat, në kërkesën e përdoruesit, gjenerojnë faqet në fluks, gjeneratorët statik janë ndërtuar pak ndryshe. Ata lejojnë marrjen e burimeve, për zakonisht është një grup skedarësh në formatin Markdown dhe shabllone, dhe më pas t'i kompiliojnë në një faqe të gatshme.
Pra, në dalje do të merrni një strukturë direktorish dhe një grup skedarësh html të gjeneruar, të cilat mund të ngarkoni thjesht në çdo host të lirë dhe të merrni një faqe funksionale.
Hugo mund të instalohet lokal dhe ta provosh në veprim:
Inicioni një faqe të re:
hugo new site docs.example.orgDhe njëkohësisht git-repozitorin:
cd docs.example.org
git initFaqja jonë është akoma e pastër dhe për të shtuar diçka, së pari na nevojitet të lidhemi me një temë. Tema është thjesht një grup templates dhe rregullash sipas të cilave gjenerohet faqja jonë.
Si temë do të përdorim , që mendoj se përshtatet më së miri për një faqe dokumentacioni.
Një vëmendje të veçantë duhet t'i kushtohet faktit se nuk na nevojitet të ruajmë skedarët e temës në depozitat tona të projektit; përkundrazi, ne mund ta lidhim atë duke përdorur git submodule:
git submodule add https://github.com/matcornic/hugo-theme-learn themes/learnNë këtë mënyrë, depozita jonë do të përmbajë vetëm skedarët që i përkasin drejtpërdrejt projektit tonë, dhe tema e lidhur do të mbetet si një lidhje në një depozitë specifike dhe commit në të, që do të thotë se gjithmonë mund ta tërheqim nga burimi origjinal dhe nuk duhet të frikësohemi nga ndryshimet e papajtueshme.
Le të rregullojmë konfigurimin config.toml:
baseURL = "http://docs.example.org/"
languageCode = "en-us"
title = "My Docs Site"
theme = "learn"Që në këtë fazë mund të startojmë:
hugo serverDhe në adresën kontrolloni faqen tonë të sapokrijuar, të gjitha ndryshimet e bëra në direktorium automatikisht përditësojnë dhe faqja e hapur në shfletues është shumë e përshtatshme!
Le të përpiqemi të krijojmë një faqe kryesore në content/_index.md:
# My docs site
## Welcome to the docs!
You will be very smart :-)Pamja e ekranit e faqes së sapokrijuar

Për të gjeneruar faqen, mjafton të startoni:
hugoPërmbajtja e direktoriumit publik/ do të jetë faqja juaj.
Po, për të thënë, le ta fusim menjëherë në .gitignore:
echo /public > .gitignoreMos harroni të komitoni ndryshimet tona:
git add .
git commit -m "New site created"2. Përgatitja e Dockerfile
Ka ardhur koha të përcaktojmë strukturën e depozita tonë. Zakonisht përdor diçka të tillë:
.
âââ deploy
â âââ app1
â âââ app2
âââ dockerfiles
âââ image1
âââ image2- dockerfiles/ â pĂ«rmbajnĂ« direktoriet me Dockerfile dhe gjithçka tĂ« nevojshme pĂ«r ndĂ«rtimin e imazheve tona docker.
- deploy/ â pĂ«rmban direktoriet pĂ«r zhvillimin e aplikacioneve tona nĂ« Kubernetes
Kështu që Dockerfile ynë i parë do ta krijojmë në rrugë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ërjashtojë nga imazhi përfundimtar docker çdo gjë të panevojshme.
KĂ«shtu imazhi pĂ«rfundimtar do tĂ« pĂ«rmbajĂ« vetĂ«m darkhttpd (njĂ« server HTTP tĂ« lehtĂ«) dhe publik/ â pĂ«rmbajtjen e faqes sonĂ« tĂ« gjeneruar statikisht.
Mos harroni të komitoni ndryshimet tona:
git add dockerfiles/website
git commit -m "Shto Dockerfile për faqen"3. Njohuni me kaniko
Si ndërtues i imazheve docker, vendosa të përdor , pasi për funksionimin e tij nuk kërkohet një demon docker, dhe ndërtimi mund të bëhet në çdo makinë dhe të ruhet cache direkt në registri, duke eliminuar kështu nevojën për një ruajtje të plotë.
Për ndërtimin e imazhit mjafton të lançoni një kontenier me kaniko executor dhe t'i transmetoni atij kontekstin aktual të ndërtimit, diçka që mund ta bëni dhe lokalisht, 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, pas ndĂ«rtimit do tĂ« dĂ«rgohet automatikisht nĂ« registrin docker.
Parametri âcache lejon tĂ« ruajĂ« shtresat nĂ« docker registry, pĂ«r shembullin e dhĂ«nĂ« ato do tĂ« ruhen nĂ« registry.gitlab.com/kvaps/docs.example.org/website/cache, por mund tĂ« tregoni njĂ« rrugĂ« tjetĂ«r duke pĂ«rdorur parametrin --cache-repo.
Kapja e ekranit docker-registry

4. Njohja me qbec
është një mjet deployimi që lejon të përshkruani deklarativisht manifestet e aplikacionit tuaj dhe t'i deployoni ato në Kubernetes. Përdorimi i Jsonnet si sintaksë kryesore e thjeshton shumë përshkrimin e diferencave për mjedise të shumta, si dhe shp almost e eliminon përsëritjen e kodit.
Kjo mund të jetë veçanërisht relevante në rastet kur ju nevojitet të deployoni një aplikacion në disa klasterë me parametra të ndryshëm dhe dëshironi të përshkruani ata deklarativisht në Git.
Qbec gjithashtu lejon të renderoni Helm chart duke u kaluar atyre parametrat e nevojshëm dhe më pas të punoni me to ashtu si me manifestet e zakonshme, duke përfshirë duke u vendosur mbi ta ndryshime të ndryshme, dhe kjo, nga ana e saj, lejon që të eliminohet nevoja për të përdorur ChartMuseum. Do të thotë, mund të ruani dhe renderoni chartet direkt nga git, ku mjekët e tyre janë.
Siç thashë më parë, të gjitha deploy-t do t'i ruajmë në direktorinë deploy/:
mkdir deploy
cd deployLe të inicializojmë aplikacionin tonë të parë:
qbec init website
cd websiteStruktura e aplikacionit tonë tani duket kështu:
.
âââ components
âââ environments
â âââ base.libsonnet
â âââ default.libsonnet
âââ params.libsonnet
âââ qbec.yamltĂ« 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 tashmë ka krijuar për ne ambientin default dhe ka marrë adresën e serverit, si dhe namespace nga kubeconfig-i ynë aktual.
Tani kur bëhet deploy në default ambient, qbec gjithmonë do të bëjë deploy vetëm në Kubernetes-cluster-in e përcaktuar dhe në namespace-in e caktuar, pra nuk do t'ju duhet më të kaloni mes kontekstesh dhe namespace-esh për të realizuar deploy.
Në rast nevoje, gjithmonë mund të azhurnoni cilësimet në këtë skedar.
Të gjitha ambientet tuaja përshkruhen në qbec.yaml, dhe në skedarin params.libsonnet, ku thuhet se nga ku duhet të merrni parametrat për to.
Më tej shohim dy direktorë:
- components/ â kĂ«tu do tĂ« ruhen tĂ« gjitha manifestet pĂ«r aplikacionin tonĂ«, ato mund tĂ« pĂ«rshkruhen si nĂ« jsonnet ashtu edhe nĂ« skedarĂ«t e zakonshĂ«m yaml
- mjediset/ â kĂ«tu do tĂ« pĂ«rshkruajmĂ« tĂ« gjitha variablat (parametrat) pĂ«r mjediset tona.
Me përjashtim të rastit, ne kemi dy skedarë:
- mjediset/base.libsonnet â ai do tĂ« pĂ«rmbajĂ« parametrat e pĂ«rbashkĂ«t pĂ«r tĂ« gjitha mjediset
- mjediset/default.libsonnet â pĂ«rmban parametrat e tejkaluar pĂ«r mjedisin default
Le të hapim mjediset/base.libsonnet dhe të shtojmë parametrat për komponentin tonë të parë:
{
komponentet: {
website: {
emri: 'example-docs',
imazhi: 'registry.gitlab.com/kvaps/docs.example.org/website:v0.0.1',
replika: 1,
portaEkonfiguratorit: 80,
portaESherbimit: 80,
përzgjedhësiINodit: {},
tolerancat: [],
klasaEPërshkimit: 'nginx',
domeni: 'docs.example.org',
},
},
}Të krijojmë gjithashtu komponentin tonë të parë komponentet/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,
},
},
],
},
},
],
},
},
]Në këtë skedar, ne përshkruam tri entitete të Kubernetes, këto janë: Deployment, Shërbimi dhe Ingress. Nëse dëshironim, mund t'i ndanim ata në komponentë të ndryshëm, por në këtë fazë një është e mjaftueshme për ne.
Sintaksa jsonnet është shumë e ngjashme me json-in e zakonshëm, në të vërtetë json-i i zakonshëm është një jsonnet i vlefshëm, kështu që për një kohë të parë mund t'ju duket më e lehtë të përdorni shërbime online si yaml2json për të konvertuar yaml-in tuaj të zakonshëm në json, ose, nëse komponentët tuaj nuk përmbajnë variabla, atëherë ata mund të përshkruhen si yaml i zakonshëm.
Kur punoni me jsonnet unë ju rekomandoj shumë të instaloni një plugin për redaktorin tuaj
Për shembuj, për vim ka një plugin vim-jsonnet, i cili përfshin ndriçimin e sintaksës dhe ekzekuton automatikisht jsonnet fmt me çdo ruajtje (kërkon që jsonnet të jetë instaluar).
Të gjitha janë gati, tani mund të fillojmë të depelojmë:
Për ta parë se çfarë kemi arritur, ekzekutojmë:
qbec show defaultNë përfundim do të shihni manifestet yaml të renderuara që do të aplikohen në klastrin default.
Shkëlqyer, tani aplikojmë:
qbec apply defaultNë përfundim gjithmonë do të shihni se çfarë do të bëhet në klastrin tuaj, qbec do t'ju kërkojë të pranoni ndryshimet, duke shkruar y do t'alejoni qëllimet tuaja.
Tani aplikacioni ynë është i vendosur!
Në rast se bëni ndryshime, gjithmonë mund të ekzekutoni:
qbec diff defaultpër të parë se si këto ndryshime do të reflektohen në vendosjen aktuale
Mos harroni të komitoni ndryshimet tona:
cd ../..
git add deploy/website
git commit -m "Shtoni vendosjen për uebfaqen"5. Po provojmë Gitlab-runner me Kubernetes-executor
Derisa kohët e fundit kam përdorur vetëm gitlab-runner në një makinë të përgatitur paraprakisht (në kontenier LXC) me executor shell ose docker. Fillimisht kishim disa nga këta ranerë të përcaktuar globalisht në Gitlab-in tonë. Ata grumbullonin imazhe docker për të gjithë projektet.
Por siç tregoi praktika â kjo zgjidhje nuk ishte mĂ« e mira, si pĂ«r nga prakticiteti ashtu edhe pĂ«r nga siguria. MĂ« mirĂ« dhe ideologjikisht ishte tĂ« kisha ranerĂ« tĂ« veçantĂ« tĂ« vendosur pĂ«r secilin projekt, ndoshta edhe pĂ«r secilĂ«n mjedis.
Me fat kjo nuk është aspak një problem, sepse tani do të vendosim gitlab-runner drejtpërdrejt si pjesë e projektit tonë në Kubernetes.
Gitlab ofron njĂ« helm-chart tĂ« gatshĂ«m pĂ«r vendosjen e gitlab-runner nĂ« Kubernetes. KĂ«shtu qĂ« gjithçka qĂ« ju nevojitet, Ă«shtĂ« tĂ« mĂ«soni registration token pĂ«r projektin tonĂ« nĂ« Settings â> CI / CD â> Runners dhe t'ja jepni 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 â tokeni i regjistrimit pĂ«r projektin tuaj.
- rbac.create=true â i jep running-it numrin e nevojshĂ«m tĂ« privilegjeve pĂ«r tĂ« krijuar podĂ« pĂ«r tĂ« bĂ«rĂ« detyrat tona me ndihmĂ«n e kubernetes-executor.
Nëse gjithçka është bërë siç duhet, duhet të shihni running-un e regjistruar në seksionin Runners, në cilësimet e projektit tuaj.
Screenshot i running-ut të shtuar

A Ă«shtĂ« kaq e thjeshtĂ«? â po, kaq e thjeshtĂ«! AsnjĂ« mĂ« shumĂ« mundimes me regjistrimin manual tĂ« running-Ă«ve, nga ky moment running-Ă«t do tĂ« krijohen dhe asgjĂ«sohen automatikisht.
6. Deploy Helm-charts me QBEC
Tani që kemi vendosur ta shqyrtojmë gitlab-runner si pjesë e projektit tonë, është koha të përshkruajmë atë në depo git.
Mund tĂ« pĂ«rshkruajmĂ« atĂ« si njĂ« komponent tĂ« veçantĂ« website, por nĂ« tĂ« ardhmen planifikojmĂ« tĂ« bĂ«jmĂ« deploy kopje tĂ« ndryshme website shumĂ« shpesh, ndryshe nga gitlab-runner, i cili do tĂ« deployohet vetĂ«m njĂ« herĂ« pĂ«r çdo Kubernetes-cluster. Pra, le tĂ«ćć§ćojmĂ« njĂ« aplikacion tĂ« veçantĂ« pĂ«r tĂ«:
cd deploy
qbec init gitlab-runner
cd gitlab-runnerKëtë herë nuk do të përshkruajmë entitetet Kubernetes manualisht, por do të marrim një Helm-chart të gatshëm. Një nga përparësitë e qbec është mundësia për të renderuar Helm-chartet drejtpërdrejt nga repository Git.
Le të lidhim atë duke përdorur git submodule:
git submodule add https://gitlab.com/gitlab-org/charts/gitlab-runner vendor/gitlab-runnerTani direktoria vendor/gitlab-runner ka një repository me chartin për gitlab-runner.
Në mënyrë të ngjashme, mund të lidhni edhe repo të tjera, për shembull edhe një repo të plotë me chartet zyrtare.
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 e kalojmĂ« rrugĂ«n pĂ«r nĂ« chart, pastaj params.values, tĂ« cilat do tâi marrim nga parametrat e mjedisit, pastaj vjen njĂ« objekt me
- nameTemplate â emri i versionit
- namespace â namespace qĂ« i kalon Helm-it
- thisFile â njĂ« parametĂ«r i detyrueshĂ«m, qĂ« kalon rrugĂ«n pĂ«r nĂ« skedarin aktual
- verbose â tregon komandĂ«n helm template me tĂ« gjitha argumentet gjatĂ« renderimit tĂ« chartit
Tani do të përshkruajmë parametrat për komponentin tonë në mjediset/base.libsonnet:
sekretet lokale = import '../secrets/base.libsonnet';
{
komponentet: {
gitlabRunner: {
emri: 'gitlab-runner',
vlerat: {
gitlabUrl: 'https://gitlab.com/',
rbac: {
krijo: true,
},
runnerRegistrationToken: sekretet.runnerRegistrationToken,
},
},
},
}Kërkojmë vëmendje runnerRegistrationToken ne marrim nga një skedar jasht secrets/base.libsonnet, le të krijojmë atë:
{
runnerRegistrationToken: 'yga8y-jdCusVDn_t4Wxc',
}Të shohim nëse gjithçka funksionon:
qbec show defaultnëse gjithçka është në rregull, atëherë mund të fshini versionin tonë të mëparshëm të lançuar përmes Helm:
helm uninstall gitlab-runnerdhe ta lançojmë atë përsëri, por tashmë përmes qbec:
qbec apply default7. Njoftimi me git-crypt
â Ă«shtĂ« njĂ« mjet qĂ« lejon tĂ« konfigurohet enkriptimi transparent pĂ«r repozitorin tuaj.
Aktualisht, struktura e drejtorisë tonë për gitlab-runner duket kështu:
.
âââ komponentet
â âââ gitlab-runner.jsonnet
âââ ambientet
â âââ base.libsonnet
â âââ default.libsonnet
âââ params.libsonnet
âââ qbec.yaml
âââ sekretet
â âââ base.libsonnet
âââ vendor
âââ gitlab-runner (submodul)Por ruajtja e sekretĂ«ve nĂ« Git Ă«shtĂ« e pasigurt, apo jo? Prandaj na nevojitet t'i enkriptojmĂ« ato nĂ« mĂ«nyrĂ« tĂ« duhur.
Zakonisht për një variabël të vetëm, kjo nuk ka gjithmonë kuptim. Ju mund të kaloni sekretet në qbec dhe përmes variablave të mjedisit të CI-sistemit tuaj.
Megjithatë, është e rëndësishme të theksohet se ka projekte më të komplikuara, të cilat mund të përmbajnë shumë më tepër sekrete, dhe ndarja e të gjitha këtyre përmes variablave të mjedisit do të ishte shumë e vështirë.Për më tepër, në këtë rast nuk do të mund t'ju tregoja për një mjet kaq të shkëlqyer si git-crypt.
git-crypt po ashtu është i dobishëm sepse ruan të gjithë historinë e sekreteve, si dhe lejon krahasimin, bashkimin dhe zgjidhjen e konflikteve ashtu siç jemi mësuar ta bëjmë me Git.
Gjëja e parë që duhet të bëjmë pas instalimit git-crypt është të gjenerojmë çelësat për depozitat tona:
git crypt initNëse keni një çelës PGP, mund ta shtoni menjëherë veten si bashkëpunëtor për këtë projekt:
git-crypt add-gpg-user kvapss@gmail.comKështu, gjithmonë do të jeni në gjendje të dekriptoni këtë depo me çelësin tuaj privat.
Nëse nuk keni një çelës PGP dhe nuk planifikoni të keni, mund të zgjidhni një rrugë tjetër dhe të eksportoni çelësin e projektit:
git crypt export-key /path/to/keyfileKështu, kushdo që ka çelësin e eksportuar keyfile do të mund të dekriptojë depozitën tuaj.
Ka ardhur koha për të konfigurimin e sekreteve tona të para.
Të rikujtojmë, ne ende jemi në direktorinë deploy/gitlab-runner/, ku e kemi një direktori secrets/, le të enkriptojmë të gjitha skedarët në të, për këtë do të krijojmë skedarin secrets/.gitattributes me këtë përmbajtje:
* filter=git-crypt diff=git-crypt
.gitattributes !filter !diffSiç shihet nga përmbajtja, të gjitha skedarët sipas maskës * do të kalojnë përmes git-crypt, përveç vetë .gitattributes
Këtë mund ta kontrollojmë duke ekzekutuar:
git crypt status -eNë dalje do të marrim një listë të të gjitha skedarëve në depo për të cilët është aktivizuar enkriptimi
Ja ku jemi, tani mund të angazhojmë ndryshimet tona me besim:
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 skedarët e enkriptuar do të shndërrohen në diçka binarike, do të jetë e pamundur t'i lexoni ato.
Për të dekriptuar depozitën, ekzekutoni:
git crypt unlock8. Krijoni imazhin e toolbox
Imazhi i toolbox është një imazh me të gjitha mjetet që do të përdorim për implikimin e projektit tonë. Ai do të përdoret nga gitlab-runner për të kryer detyra tipike të implikimit.
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 si duket, në këtë imazh ne instaluam të gjitha utilitetet që përdorëm për të dëbuar aplikacionin tonë. Këtu nuk kemi nevojë për kubectl, por ndoshta do të dëshironit të luanit me të në fazën e konfigurimit të pipeline-it.
Po ashtu, për të qenë në gjendje të komunikojmë me Kubernetes dhe të kryejmë deploje 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:
cd deploy/gitlab-runnerdhe do të shtojmë një komponent të 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 të 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',
},
},
}Kërkojmë vëmendje $.components.rbac.name i referohet emri për komponentin rbac
Le të verifikojmë se çfarë ka ndryshuar:
qbec diff defaultdhe të aplikojmë ndryshimet tona në Kubernetes:
qbec apply defaultMos harrojmë të angazhojmë ndryshimet tona në git:
cd ../..
git add dockerfiles/toolbox
git commit -m "Shto Dockerfile për toolbox"
git add deploy/gitlab-runner
git commit -m "Konfiguro gitlab-runner për të përdorur toolbox"9. Të parin tonë pipeline 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 përdorim GIT_SUBMODULE_STRATEGY: normal për ato detyra ku duhet të inicializojmë në mënyrë të qartë submodulin para ekzekutimit.
Mos harroni të komitoni 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 një etiketë:
git tag v0.0.1Ne do t'i vendosim etiketat çdo herĂ« qĂ« na nevojitet tĂ« lĂ«shojmĂ« njĂ« version tĂ« ri. Etiketat nĂ« imazhet Docker do tĂ« lidhen me etiketat Git. Ădo push me njĂ« etiketĂ« tĂ« re do tĂ« inicojĂ« ndĂ«rtimin e imazheve me kĂ«tĂ« etiketĂ«.
Do ta kryejmë git push --tags, dhe do të shikojmë në pipeline tonë të parë:
Screenshot i pipeline-t të parë

Vlen të theksohet se ndërtimi për etiketa është i përshtatshëm për ndërtimin e imazheve docker, por nuk është i përshtatshëm për depolimin e aplikacionit në Kubernetes. Duke qenë se etiketa të reja mund të caktohen edhe për komitë të vjetra, në këtë rast inicoimi i pipeline-t për to do të çojë në depolimin e versionit të vjetër.
Për të zgjidhur këtë problem, zakonisht ndërtimi i imazheve docker lidhet me etiketat, ndërsa depolimi i aplikacionit me degën master, në të cilën janë të ngurtësuara versionet e imazheve të ndërtuara. Vetëm në këtë rast mund të inicojme një kthim mbrapa me një revert master-dege.
10. Automatizimi i depolimit
Në mënyrë që Gitlab-runner të mund të deshifrojë sekretet tona, do të na nevojitet të eksportojmë çelësin e repository-t dhe ta shtojmë atë në variablat mjedisore të CI-së tonë:
git crypt export-key /tmp/docs-repo.key
base64 -w0 /tmp/docs-repo.key; echostringun e marrë do ta ruajmë në Gitlab, për këtë do të kalojmë në konfigurimet e projektit tonë:
C ĐœĐ°ŃŃŃĐŸĐčĐșĐž â> CI / CD â> Variables
Dhe do të krijojmë një variabël të re:
Tipi
Key
Vlera
E mbrojtur
E maskuar
Shkalla
File
GITCRYPT_KEY
<stringu juaj>
e vërtetë (për kohën e trajnimit, mund edhe false)
e vërtetë
TĂ« gjitha ambientet
Screenshot i variablës së shtuar

Tani do ta azhurnojmë tonë .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 ne kemi përdorur disa mundësi të reja për qbec:
- âroot some/app â lejon tĂ« pĂ«rcaktoni direktorine e aplikacionit specifik
- âforce:k8s-context __incluster__ â kjo Ă«shtĂ« njĂ« variabĂ«l magjike qĂ« tregon se deploy do tĂ« ndodhi nĂ« tĂ« njĂ«jtin klaster ku Ă«shtĂ« nisur gtilab-runner. Duhet ta bĂ«ni kĂ«tĂ«, pasi ndryshe qbec do tĂ« provojĂ« tĂ« gjejĂ« njĂ« server Kubernetes tĂ« pĂ«rshtatshĂ«m nĂ« kubeconfig tuaj
- âwait â e bĂ«n qbec tĂ« presĂ« derisa burimet e krijuara tĂ« kalojnĂ« nĂ« gjendjen Ready dhe pastaj tĂ« pĂ«rfundojnĂ« me njĂ« exit-code tĂ« suksesshĂ«m.
- âyes â thjesht çon nĂ« mbylljen e shell-it interaktiv A jeni tĂ« sigurt? nĂ« deploy.
Mos harroni të komitoni ndryshimet tona:
git add .gitlab-ci.yml
git commit -m "Automate deploy"Dhe pas git push do të shohim si u kanë dëshkuar aplikacionet tona:
Screenshot i pipeline-it të dytë

11. Artefaktet dhe ndërtimi gjatë push në master
Në përgjithësi, hapat e mësipërm janë të mjaftueshëm për ndërtimin dhe shpërndarjen e pothuajse çdo mikroshërbimi, por ne nuk duam të vendosim një etiketë çdo herë kur na nevojitet të përditësojmë faqen. Prandaj, do të ndjekim një rrugë më dinamike dhe do të konfigurojmë shpërndarjen sipas digest në degën master.
Ideja është e thjeshtë: tani imazhi ynë website do të ricampohet çdo herë kur bëhet një push në master, dhe më pas automatikisht do të shpërndahen në Kubernetes.
Le të përditësojmë 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 për refs për punën build_website dhe tani po përdorim $CI_COMMIT_REF_NAME në vend të $CI_COMMIT_TAG, pra ndaj ne ndalojmë lidhjen me etiketat në Git dhe tani do të dorëzojmë imazhin me emrin e degës së komitit që aktivizoi pipeline. Vlen të theksohet se kjo do të funksionojë gjithashtu me etiketat, duke na lejuar të ruajmë snapshotet e faqes me një version të caktuar në docker-registry.
Kur emri i etiketës docker për versionin e ri të faqes mund të mbetet i pandryshuar, ne ende duhet të përshkruajmë ndryshimet për Kubernetes, në të kundërt do të thotë se ai thjesht nuk do të ri-distribuojë aplikacionin nga imazhi i ri, pasi nuk do të vërejë asnjë ndryshim në manifestin e shpërndarjes.
Opcioni âvm:ext-str digest=»$DIGEST» pĂ«r qbec â lejon tĂ« kalosh njĂ« variabĂ«l tĂ« jashtme nĂ« jsonnet. Ne duam qĂ« me çdo lĂ«shim tĂ« aplikacionit tonĂ« tĂ« ri-distribuohet nĂ« klasĂ«r. Tani nuk mund tĂ« pĂ«rdorim emrin e etiketĂ«s qĂ« tani mund tĂ« mbetet i pandryshuar, pasi duhet tĂ« lidhim nĂ« njĂ« version tĂ« caktuar tĂ« imazhit dhe tĂ« aktivizojmĂ« shpĂ«rndarjen kur ai ndryshon.
KĂ«tu na ndihmon mundĂ«sia e Kaniko pĂ«r tĂ« ruajtur digestin e imazhit nĂ« njĂ« skedar (opsioni âdigest-file)
Pastaj këtë skedar do ta kalojmë dhe e lexojmë në momentin e shpërndarjes.
Do të përmirë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',
},
},
}I gatshëm, tani çdo komitim në master do të inicializojë ndërtimin e imazhit docker për website, dhe pastaj do ta vendosë atë në Kubernetes.
Mos harroni të komitoni ndryshimet tona:
git add .
git commit -m "Configure dynamic build"Le të kontrollojmë, pas git push duhet të shohim diçka të tillë:
Screenshot i pipeline për master

Nësë e kemi të panevojshme të ri-vendosim gitlab-runner pas çdo dorëzimi, nëse, sigurisht, asgjë nuk është ndryshuar në konfigurimin e tij, le të e 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/**/*ndryshime do të lejojë të monitorojmë ndryshimet në deploy/gitlab-runner/ dhe do të aktivizojë punën tonë vetëm në rast të tillë
Mos harroni të komitoni ndryshimet tona:
git add .gitlab-ci.yml
git commit -m "Reduce gitlab-runner deploy"git push, kështu është më mirë:
Screenshot i pipeline-it të përditësuar

12. Ambientet dinamike
Ka ardhur koha të diversifikojmë pipeline-in tonë me ambiente dinamike.
Së pari, le të përditësojmë punën build_website në tonin tonë .gitlab-ci.yml, duke e hequr bllokun vetëm, që do të detyrojë Gitlab të 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/Pastaj do të përditësojmë punën deploy_website, do të shtojmë një bllok environment:
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ë lejojë Gitlab të asociojë punën me prod ambientin dhe të shfaqë lidhjen e duhur për të.
Tani do të shtojmë edhe dy punë:
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: manualDo të aktivizohen me push në çdo degë përveç master dhe do të lançojnë versionin paraprak të faqes.
Shohim njĂ« opsion tĂ« ri pĂ«r qbec: âapp-tag â lejon tĂ« etiketosh versionet e lançuara tĂ« aplikacionit dhe tĂ« punosh vetĂ«m brenda kĂ«saj etikete; nĂ« krijimin dhe shkatĂ«rrimin e burimeve nĂ« Kubernetes, qbec do tĂ« operojĂ« vetĂ«m me to.
Kështu, ne mund të mos krijojmë një ambient të veçantë për çdo review, por thjesht të ripërdorim të njëjtin.
KĂ«tu po ashtu pĂ«rdorim qbec apply review, nĂ« vend tĂ« qbec apply default â kjo Ă«shtĂ« pikĂ«risht ajo moment kur do tĂ« pĂ«rpiqemi tĂ« pĂ«rshkruajmĂ« dallimet pĂ«r ambientet tona (review dhe default):
Do të shtojmë review ambientin në deploy/website/qbec.yaml
spec:
ambientet:
review:
defaultNamespace: docs
server: https://kubernetes.example.org:8443Pastaj do ta shpallim atë 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 'ambienti ' + env + ' nuk është i definuar në ' + std.thisFileDhe do të shkruajmë parametra personalizuar për të 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 gjithashtu më me kujdes punën 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ë do të klonojmë master-degën dhe do të fshijmë review përmes saj.
Pak e ndërlikuar, por nuk kam gjetur një mënyrë më të bukur deri tani.
Një alternativë mund të jetë deployment-i i çdo review në një hapësirë të veçantë, e cila gjithmonë mund të hiqet komplet.
Mos harroni të komitoni ndryshimet tona:
git add .
git commit -m "Aktivizo automatic review"git push, git checkout -b test, git push origin test, verifikohet:
Screenshoti i ambienteve të krijuara në Gitlab

A gjithçka funksionon? â shkĂ«lqyeshĂ«m, le tĂ« fshijmĂ« degĂ«n tonĂ« testuese: git checkout master, git push origin :test, verifikohet qĂ« punĂ«t pĂ«r fshirjen e ambientit kanĂ« pĂ«rfunduar pa gabime.
Këtu është mirë të sqarojmë se çdo zhvillues në projekt mund të krijojë degë, gjithashtu ai mund të modifikojë .gitlab-ci.yml skedarin dhe të ketë akses në variablat sekrete.
Prandaj, rekomandohet fuqishëm të lejohet përdorimi i tyre vetëm për degët e mbrojtura, për shembull në master, ose të krijohet një grup i veçantë variablash për çdo ambient.
13. Review Apps
këto janë mundësitë e Gitlab që lejojnë çdo skedë në depo të ketë një buton për shikimin e shpejtë në ambientin e deploy-uar.
Për t'i pasur këto butona, duhet të krijoni skedarin .gitlab/route-map.yml dhe të përshkruani aty të gjitha transformimet e rrugëve, në rastin tonë kjo do të jetë shumë e thjeshtë:
# Indices
- source: /content/(.+?)_index.(md|html)/
public: '1'
# Pages
- source: /content/(.+?).(md|html)/
public: '1/'Mos harroni të komitoni ndryshimet tona:
git add .gitlab/
git commit -m "Aktivizo aplikacionet e rishikimit"git push, dhe verifikohet:
Screenshoti i butonit Review App

Puna u krye!
Burimet e projektit:
- në Gitlab:
- në GitHub:
Faleminderit për vëmendjen, shpresoj se ju pëlqeu ![]()
Burimi: habr.com
